从字节码角度分析以下几点:

  1. 内部类可以直接访问外部类的private字段和方法;
  2. 非静态内部类持有外部类的引用;
  3. 外部类可以直接访问内部类的private字段和方法(不管是不是静态内部类);

搜索“解释”二字即可从文中得到答案

示例java

package com.fqxyi;

class Test {

    public Test() {
        //用于解释外部类可以直接访问内部类的private字段和方法(不管是不是静态内部类)
        testB();
    }

    private int count;

    private static int count_static;

    public static void main(String[] args) {
        A a = new A();
        a.printA();
    }

    static class A {
        private void printA() {
            //用于解释静态内部类可以直接访问外部类的private字段和方法
            System.out.println("print log --> a count_static = " + count_static);
        }
    }

    private void testB() {
        B b = new B();
        b.printB();
    }

    //用于解释非静态内部类持有外部类的引用
    class B {
        private void printB() {
            //用于解释内部类可以直接访问外部类的private字段和方法
            System.out.println("print log --> b count = " + count);
        }
    }
}

- 阅读剩余部分 -

暂停学习Flutter,之后学习https://book.flutterchina.club/chapter6/

Learn

Flutter中文网

来源:Flutter中文网

编写第一个Flutter应用

Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

  1. 一个 StatefulWidget类。
  2. 一个 State类。 StatefulWidget类本身是不变的,但是 State类在widget生命周期中始终存在.

Flutter Widget框架概述

Flutter有一套丰富、强大的基础widget,其中以下是很常用的:

  • Text:该 widget 可让创建一个带格式的文本。
  • Row、 Column: 这些具有弹性空间的布局类Widget可让您在水平(Row)和垂直(Column)方向上创建灵活的布局。其设计是基于web开发中的Flexbox布局模型。
  • Stack: 取代线性布局 (译者语:和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝度定位(absolute positioning )布局模型设计的。
  • Container: Container 可让您创建矩形视觉元素。container 可以装饰为一个BoxDecoration, 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container可以使用矩阵在三维空间中对其进行变换。
  • Navigator: 它管理由字符串标识的Widget栈(即页面路由栈)。Navigator可以让您的应用程序在页面之间的平滑的过渡。

StatefulWidget和State

您可能想知道为什么StatefulWidget和State是单独的对象。在Flutter中,这两种类型的对象具有不同的生命周期: Widget是临时对象,用于构建当前状态下的应用程序,而State对象在多次调用build()之间保持不变,允许它们记住信息(状态)。
在Flutter中,事件流是“向上”传递的,而状态流是“向下”传递的(译者语:这类似于React/Vue中父子组件通信的方式:子widget到父widget是通过事件通信,而父到子是通过状态),重定向这一流程的共同父元素是State。



- 阅读剩余部分 -

官网地址

本站下载地址

注意事项

  • 只支持Windows
  • 免费版本,使用直接打印(LODOP.PRINT();),底部会出现本页由【试用版打印控件Lodop6.2.2.4】输出字样。

使用总结

/*
* 打印功能
* */
import { getLodop } from '../utils/LodopFuncs'
import { MessageBox } from 'element-ui'

export default {
  /**
   * 获取初始化的Print
   */
  getInitedPrint (type) {
    const LODOP = getLodop()
    // 判断LODOP是否安装或异常
    if (!LODOP) {
      MessageBox({
        title: '提示',
        message: 'LODOP初始化异常,请前往打印机设置页面排查!',
        confirmButtonText: '去设置'
      }, (e) => {
        if (window.location.hash.indexOf('#/branch') !== -1) {
          window.location.href = window.location.href.split('#/branch')[0] + '#/branch/settings/printerConfig'
        } else if (window.location.hash.indexOf('#/master') !== -1) {
          window.location.href = window.location.href.split('#/master')[0] + '#/master/settings/printerConfig'
        } else if (window.location.hash.indexOf('#/wms') !== -1) {
          window.location.href = window.location.href.split('#/wms')[0] + '#/wms/settings/printerConfig'
        }
      })
      return false
    }
    // 尝试指定打印设备
    const dataStr = localStorage.getItem('PRINTSET')
    if (dataStr && dataStr !== 'undefined') {
      const data = JSON.parse(dataStr)// 解析数据
      // 如果SET_PRINTER_INDEX返回false,则忽略,使用默认打印设备
      if (type == 1) {
        LODOP.SET_PRINTER_INDEX(data.aSet)
      } else if (type == 2) {
        LODOP.SET_PRINTER_INDEX(data.labelSet)
      } else if (type == 3) {
        LODOP.SET_PRINTER_INDEX(data.ticketSet)
      }
    }
    return LODOP
  },
  /**
   * 打印A4纸
   */
  printA4 (id) {
    const LODOP = this.getInitedPrint(1)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.PREVIEW()
    }
  },
  /**
   * 打印A4纸 横向
   */
  printTransverseA4 (id) {
    const LODOP = this.getInitedPrint(1)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.SET_PRINT_PAGESIZE(2, 0, 0, 'A4')
      LODOP.PREVIEW()
    }
  },
  /**
   * 预览打印A4纸
   */
  previewA4 (id) {
    const LODOP = this.getInitedPrint(1)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.PREVIEW()
    }
  },
  /**
   * 打印商品标签
   */
  printLabel (id, barcode) {
    const LODOP = this.getInitedPrint(2)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.SET_PRINT_PAGESIZE(1, 800, 400, 'A4')
      LODOP.ADD_PRINT_BARCODE(120, 200, 120, 20, '128Auto', barcode)
      LODOP.PRINT()
    }
  },
  /**
   * 预览打印商品标签
   */
  previewLabel (id, barcode) {
    const LODOP = this.getInitedPrint(2)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.SET_PRINT_PAGESIZE(1, 800, 10, 'A4')
      LODOP.ADD_PRINT_BARCODE(120, 200, 120, 20, '128Auto', barcode)
      LODOP.PREVIEW()
    }
  },
  /**
   * 打印小票
   */
  printTicket (id) {
    const LODOP = this.getInitedPrint(3)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', strFormHtml)
      LODOP.SET_PRINT_PAGESIZE(3, 750, 10, '')
      LODOP.SET_PRINT_MODE('PRINT_PAGE_PERCENT', 'Height:85%')
      LODOP.PRINT()
    }
  },
  /**
   * 预览打印小票
   */
  previewTicket (id) {
    const LODOP = this.getInitedPrint(3)
    if (LODOP) {
      const strFormHtml = '<head>' + document.head.innerHTML + '</head><body>' + document.getElementById(id).innerHTML + '</body>'
      LODOP.ADD_PRINT_HTM(0, 0, '100%', '110%', strFormHtml)
      LODOP.SET_PRINT_PAGESIZE(3, 750, 20, '')
      LODOP.SET_PRINT_MODE('PRINT_PAGE_PERCENT', 'Height:85%')
      LODOP.PREVIEW()
    }
  }
}

例子

最近线上报了一个java.lang.UnsatisfiedLinkError的错误,发现环信内部没有将某个loadLibrary方法try catch(error),但是其内部的_loadLibrary方法是try catch(error)的,所以准备做以下修改:
hyphenatechat_3.4.2.jar中的EMClient.class文件中的loadLibrary方法做以下替换:

private static void loadLibrary() {
    if (!libraryLoaded) {
        _loadLibrary("sqlite");
        _loadLibrary("hyphenate_av");
        _loadLibrary("hyphenate_av_recorder");
        System.loadLibrary("hyphenate");
        libraryLoaded = true;
    }

}

替换为

private static void loadLibrary() {
    if (!libraryLoaded) {
        _loadLibrary("sqlite");
        _loadLibrary("hyphenate_av");
        _loadLibrary("hyphenate_av_recorder");
        _loadLibrary("hyphenate");
        libraryLoaded = true;
    }

}

环境

Windows

需要下载内容


- 阅读剩余部分 -

知识点

  1. ViewModelProviders:ViewModelProvider的工厂方法。
  2. ViewModelProvider:工具类,通过反射的方式创建ViewModel。
  3. AndroidViewModelFactory:ViewModelProvider的静态内部类 ,全局单例只有一个 ,用于实现反射创建ViewModel。
  4. ViewModelStores:ViewModelStore的工厂方法类。
  5. ViewModelStore:使用HashMap存储ViewModel,key为:“DEFAULT_KEY + ":" + canonicalName”。
  6. HolderFragment:系统为你的Activity添加一个具有提供ViewModelStore的Fragment,并且因为这个Fragment调用了setRetainInstance(true),所以它能够跨越activity的生命周期。

使用

ViewModelProviders.of(getActivity()).get(MainViewModel.class);

- 阅读剩余部分 -