Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

Eric6与pyqt5学习笔记 1【安装和配置】

$
0
0

一起学习pyqt吧~

==========================================================

学习配置环境,我的python环境为python3.5

PyQt5下载地址:https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.6/
Eric6下载地址:https://sourceforge.net/projects/eric-ide/files/eric6/stable/6.1.7/

First

安装pyqt5,下载对应位数的exe安装包,本地直接双击安装,全部默认到底,安装目录应该默认是你的python目录,如果不是,手动改一下

Second

eric6记得下一下汉化的那个包eric6-i18n-zh_CN-6.1.7.zip,解压后将里面的文件相同路径对应替换到eric6的解压文件中去,然后整个eric6解压文件复制到python的安装目录下,cmd进入该目录,执行python install.py,即可安装完成

启动Eric6

安装完成后进入相应目录下X:\python3.5\Lib\site-packages\eric6,点击运行eric6.pyw,即可打开eric6

作者:wy_97 发表于2017/11/24 16:09:30 原文链接
阅读:0 评论:0 查看评论

介绍 Java 8 Date/Time API

$
0
0

介绍 Java 8 Date/Time API

1.概述

java8 引入新的日期时间API,为了解决原来java.util.Date , java.util.Calendar的一些缺陷。

本文首先介绍原Date,Calendar API的问题,然后来说明java8 Date , Time API是如何解决的。

同时,我们也了解java8中java.time包中一些常用类及其API,如LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Period, Duration.

2.原Date/Time APIs问题

  • 线程安全 —— Date和Calendar类不是线程安全的,在调试并发程序时让人头痛,开发者必须自己额外的代码处理线程安全。相反,java8中引入新的Date和Time API是不可变且线程安全的,因为开发者无需单向并发问题。

  • 简单易懂 —— Date和Calendar类

  • 时区和时间 —— 使用原来的API开发者不得不写额外逻辑处理时区逻辑,因此新的API可以使用Local、ZoneDate/TimeAPI处理时区问题。

3.使用LocalDate,LocalTime,LocalDateTime类API

最常用的类是LocalDate, LocalTime, LocalDateTime,见名思意,它们分别表示当前上下文的本地日期/时间。
这些类主要用在时区无需显示指定的场景。本节让介绍其最常用的API.

3.1.使用LocalDate

LocalDate 表示ISO格式日期 (yyyy-MM-dd),没有时间。
可以用来存储日期,如生日,付款日期等。当前日期可以用系统时钟创建:
LocalDate localDate = LocalDate.now();

LocalDate表示特定年,月,日,可以使用of方法或parse方法创建。举例:

LocalDate.of(2015, 02, 20);

LocalDate.parse("2015-02-20");

LocalDate提供多个工具方法可以获得不同信息。让我们快速了解下。
下面代码片段获得本地日期,然后加一天:

LocalDate tomorrow = LocalDate.now().plusDays(1);LocalDate tomorrow = LocalDate.now().plusDays(1);

下面代码获得当前日期,然后减去一个月。注意其枚举时间单位参数:

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);

下面两行代码解析“2016-06-12”,然后获取星期几和月中那一天。注意其返回值,第一个为DayOfWeek,第二个是int。

DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek();

int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();

也可以轻松测试闰年,示例代码如下:

boolean leapYear = LocalDate.now().isLeapYear();

两个日期比较,before和after很便捷:

boolean notBefore = LocalDate.parse("2016-06-12").isBefore(LocalDate.parse("2016-06-11"));

boolean isAfter = LocalDate.parse("2016-06-12").isAfter(LocalDate.parse("2016-06-11"));

可以从日期中获取边界。下面示例分别获取当天的开始及当月的第一天。

LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay();
LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12").with(TemporalAdjusters.firstDayOfMonth());

下面我们看看LocalTime类。

3.2 使用LocalTime

LocalTime表示时间,没有日期。与LocalDate类似,LocalTime能通过of和parse方法从系统时钟创建。
下面通过示例了解下常用API.

LocalTime now = LocalTime.now();

下面代码示例,我们通过解析字符串创建LocalTime表示06:30AM。

LocalTime sixThirty = LocalTime.parse("06:30");

也可以使用工厂方法创建LocalTime。示例如下:

LocalTime sixThirty = LocalTime.of(6, 30);

通过plus方法增加一小时。servenThirth为07:30AM.

LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);

提供便捷的方法获取时间单元。

int six = LocalTime.parse("06:30").getHour();

比较日期,是否晚于或早于特定时间。示例代码:

boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));

LocalTime类中通过常量可以获得max,min,noon时间。在执行数据库时间范围查询时非常有用。下面代码表示23:59:59.99.

LocalTime maxTime = LocalTime.MAX

下面看看LocalDateTime类。

3.3使用LocalDateTime

LocalDateTime表示日期和时间组合。这时最常用的类,提供了丰富的API.

通过从系统时钟创建:

LocalDateTime.now();

通过工厂方法of或parse创建:
LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

LocalDateTime.parse("2015-02-20T06:30:00");

提供了工具API实现增加或减少单元日期或时间。如年,月,日,分钟等。

localDateTime.plusDays(1);

localDateTime.minusHours(2);

通过get方法获取时间单元。

localDateTime.getMonth();

4.使用ZonedDateTime

java8提供了ZonedDateTime类,用于处理带时区的日期和时间。ZoneId表示不同的时区。大约有40不同的时区。

下面代码创建一个时区:

ZoneId zoneId = ZoneId.of("Europe/Paris");

获取所有时区集合:
Set allZoneIds = ZoneId.getAvailableZoneIds();

把LocalDateTime转换成特定的时区:

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

ZonedDateTime提供parse方法获得特定时区的dateTime:

ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");

另外和时区一起使用的类是OffsetDateTime类,OffsetDateTime是不变的,表示date-time偏移,存储所有日期和时间字段,精确至纳秒,从UTC/Greenwich计算偏移。

可以通过OffSetDateTime实例结合ZoneOffset创建LocalDateTime。
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

我们创建ZoneOffset,增加两个小时:

ZoneOffset offset = ZoneOffset.of("+02:00");

OffsetDateTime offSetByTwo = OffsetDateTime.of(localDateTime, offset);

先localDateTime的值为 2015-02-20 06:30 +02:00.

下面我们看如何通过Period和Duration类修改日期和时间值。

5.使用Period 和 Duration

Period类代表年,月,日的时间量,Duration类代表秒和纳秒的数量。

5.1使用Period

Period类主要用来修改给定日期值,或获取两日期之间的差值:

LocalDate initialDate = LocalDate.parse("2007-05-10");

通过Period可以操作日期:

LocalDate finalDate = initialDate.plus(Period.ofDays(5));

Period类有不同的get方法,如getYears,getMonths,getDays可以获得不同周期值。下面代码返回5,反应日期间隔:

int five = Period.between(finalDate, initialDate).getDays();

也可以通过ChronoUnit实现通用功能:

int five = ChronoUnit.DAYS.between(initialDate , initialDate);

使用Duration

与Period类似, Duration类用于处理时间, 下面代码创建LocalTime然后增加30秒。

LocalTime initialTime = LocalTime.of(6, 30, 0);

LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));

两个时间之间间隔通过Duration类获得时间单元。
int thirty = Duration.between(finalTime, initialTime).getSeconds();
通用可以通过ChronoUnit 类获得。
int thirty = ChronoUnit.SECONDS.between(finalTime, initialTime);

兼容原Date and Calendar

java8已经提供了toInstant方法,可以转换Date和Calendar实例至新的DateTime。
下面是原Date类中新增的方法:

public static Date from(Instant instant) {
    try {
        return new Date(instant.toEpochMilli());
    } catch (ArithmeticException ex) {
        throw new IllegalArgumentException(ex);
    }
}

public Instant toInstant() {
    return Instant.ofEpochMilli(getTime());
}

示例转换:
LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());

也可以通过Epoch时间构建LocalDateTime,Epoch指的是一个特定的时间:1970-01-01 00:00:00 UTC。
结果为2016-06-13T11:34:50:
LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);

7.Date and Time 格式化

java8提供了非常简单的方式格式化日期和时间:

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);

下面代码传入一个ISO日期格式去格式化一个本地时间,结果为2015-01-25:

LocalDate localDate = localDateTime.format(DateTimeFormatter.ISO_DATE);

DateTimeFormatter 类提供了多个标准格式选项。也支持自定义的格式。下面示例代码结果为2015/01/25:

localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

也可以通过格式样式格式化,如SHORT, LONG or MEDIUM 。下面代码输出为25-Jan-2015 06:30:00:

localDateTime
  .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
  .withLocale(Locale.UK);

总结

java8提供了丰富的API操作日期时间,相比较原来的API,使用更容易更便捷。如果使用jdk较低版本,可以使用joda库实现,本来java8API就是由joda提供。joda可以通过maven引入:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.4</version>
</dependency>
作者:neweastsun 发表于2017/11/24 16:34:02 原文链接
阅读:0 评论:0 查看评论

Android开发笔记: Android适配方案

$
0
0

转载请标明出处: 
http://blog.csdn.net/lmj623565791/article/details/45460089; 
本文出自:【张鸿洋的博客】

1、概述

大家在Android开发时,肯定会觉得屏幕适配是个尤其痛苦的事,各种屏幕尺寸适配起来蛋疼无比。如果我们换个角度我们看下这个问题,不知道大家有没有了解过web前端开发,或者说大家对于网页都不陌生吧,其实适配的问题在web页面的设计中理论上也存在,为什么这么说呢?电脑的显示器的分辨率、包括手机分辨率,我敢说分辨率的种类远超过Android设备的分辨率,那么有一个很奇怪的现象:

为什么Web页面设计人员从来没有说过,尼玛适配好麻烦?

那么,到底是什么原因,让网页的设计可以在千差万别的分辨率的分辨率中依旧能给用户一个优质的体验呢?带着这个疑惑,我问了下媳妇(前端人员),媳妇睁大眼睛问我:什么叫适配?fc,尼玛,看来的确没有这类问题。后来再我仔细的追问后,她告诉我,噢,这个尺寸呀,我都是设置为20%的~~追根到底,其实就是一个原因,网页提供了百分比计算大小。

同样的,大家拿到UI给的设计图以后,是不是抱怨过尼玛你标识的都是px,我项目里面用dp,这什么玩意,和UI人员解释,UI妹妹也不理解。那么本例同样可以解决Android工程师和UI妹妹间的矛盾~UI给出一个固定尺寸的设计稿,然后你在编写布局的时候不用思考,无脑照抄上面标识的像素值,就能达到完美适配,理想丰不丰满~~。

然而,Android对于不同的屏幕给出的适配方案是dp,那么dp与百分比的差距到底在哪里?

2、dp vs 百分比

  • dp

我们首先看下dp的定义:

Density-independent pixel (dp)独立像素密度。标准是160dip.即1dp对应1个pixel,计算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多。 
上面的公式中有个dpi,dpi为DPI是Dots Per Inch(每英寸所打印的点数),也就是当设备的dpi为160的时候1px=1dp;

好了,上述这些概念记不记得住没关系,只要记住一点dp是与像素无关的,在实际使用中1dp大约等于1/160inch。

那么dp究竟解决了适配上的什么问题?可以看出1dp = 1/160inch;那么它至少能解决一个问题,就是你在布局文件写某个View的宽和高为160dp*160dp,这个View在任何分辨率的屏幕中,显示的尺寸大小是大约是一致的(可能不精确),大概是 1 inch * 1 inch。

但是,这样并不能够解决所有的适配问题:

  • 呈现效果仍旧会有差异,仅仅是相近而已
  • 当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。

以上两点,来自参考链接1

一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。适配的问题还需要我们自己去做,于是我们可能会这么做:

<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <!-- values-hdpi 480X800 -->  
    <dimen name="imagewidth">120dip</dimen>      
</resources>  

<resources>  
    <!-- values-hdpi-1280x800 -->  
    <dimen name="imagewidth">220dip</dimen>      
</resources>  


<?xml version="1.0" encoding="utf-8"?>  
<resources>  
    <!-- values-hdpi  480X320 -->  
    <dimen name="imagewidth">80dip</dimen>      
</resources> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

上述代码片段来自网络,也就是说,我们为了优质的用户体验,依然需要去针对不同的dpi设置,编写多套数值文件。

可以看出,dp并没有能解决适配问题。下面看百分比。

  • 百分比 
    这个概念不用说了,web中支持控件的宽度可以去参考父控件的宽度去设置百分比,最外层控件的宽度参考屏幕尺寸设置百分比,那么其实中Android设备中,只需要支持控件能够参考屏幕的百分比去计算宽高就足够了。

比如,我现在以下几个需求:

  • 对于图片展示的Banner,为了起到该有的效果,我希望在任何手机上显示的高度为屏幕高度的1/4
  • 我的首页分上下两栏,我希望每个栏目的屏幕高度为11/24,中间间隔为1/12
  • slidingmenu的宽度为屏幕宽度的80%

当然了这仅仅是从一个大的层面上来说,其实小范围布局,可能百分比将会更加有用。

那么现在不支持百分比,实现上述的需求,可能需要1、代码去动态计算(很多人直接pass了,太麻烦);2、利用weight(weight必须依赖Linearlayout,而且并不能适用于任何场景)

再比如:我的某个浮动按钮的高度和宽度希望是屏幕高度的1/12,我的某个Button的宽度希望是屏幕宽度的1/3。

上述的所有的需求,利用dp是无法完成的,我们希望控件的尺寸可以按照下列方式编写:

   <Button
        android:text="@string/hello_world"
        android:layout_width="20%w"
        android:layout_height="10%h"/>
  • 1
  • 2
  • 3
  • 4

利用屏幕的宽和高的比例去定义View的宽和高。

好了,到此我们可以看到dp与百分比的区别,而百分比能够更好的解决我们的适配问题。

  • some 适配tips

我们再来看看一些适配的tips

  1. 多用match_parent
  2. 多用weight
  3. 自定义view解决

其实上述3点tip,归根结底还是利用百分比,match_parent相当于100%参考父控件;weight即按比例分配;自定义view无非是因为里面多数尺寸是按照百分比计算的;

通过这些tips,我们更加的看出如果能在Android中引入百分比的机制,将能解决大多数的适配问题,下面我们就来看看如何能够让Android支持百分比的概念。

3、百分比的引入

1、引入

其实我们的解决方案,就是在项目中针对你所需要适配的手机屏幕的分辨率各自简历一个文件夹。

如下图:

然后我们根据一个基准,为基准的意思就是:

比如480*320的分辨率为基准

  • 宽度为320,将任何分辨率的宽度分为320份,取值为x1-x320
  • 高度为480,将任何分辨率的高度分为480份,取值为y1-y480

例如对于800*480的宽度480:

可以看到x1 = 480 / 基准 = 480 / 320 = 1.5 ;

其他分辨率类似~~ 
你可能会问,这么多文件,难道我们要手算,然后自己编写?不要怕,下文会说。

那么,你可能有个疑问,这么写有什么好处呢?

假设我现在需要在屏幕中心有个按钮,宽度和高度为我们屏幕宽度的1/2,我可以怎么编写布局文件呢?

<FrameLayout >

    <Button
        android:layout_gravity="center"
        android:gravity="center"
        android:text="@string/hello_world"
        android:layout_width="@dimen/x160"
        android:layout_height="@dimen/x160"/>

</FrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以看到我们的宽度和高度定义为x160,其实就是宽度的50%; 
那么效果图:

可以看到不论在什么分辨率的机型,我们的按钮的宽和高始终是屏幕宽度的一半。

  • 对于设计图

假设现在的UI的设计图是按照480*320设计的,且上面的宽和高的标识都是px的值,你可以直接将px转化为x[1-320],y[1-480],这样写出的布局基本就可以全分辨率适配了。

你可能会问:设计师设计图的分辨率不固定怎么办?下文会说~

  • 对于上文提出的几个dp做不到的

你可以通过在引入百分比后,自己试试~~

好了,有个最主要的问题,我们没有说,就是分辨率这么多,尼玛难道我们要自己计算,然后手写?

2、自动生成工具

好了,其实这样的文件夹手写也可以,按照你们需要支持的分辨率,然后编写一套,以后一直使用。

当然了,作为程序员的我们,怎么能做这么low的工作,肯定要程序来实现:

那么实现需要以下步骤:

  1. 分析需要的支持的分辨率

对于主流的分辨率我已经集成到了我们的程序中,当然对于特殊的,你可以通过参数指定。关于屏幕分辨率信息,可以通过该网站查询:http://screensiz.es/phone

  1. 编写自动生成文件的程序

代码如下

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

/**
 * Created by zhy on 15/5/3.
 */
public class GenerateValueFiles {

    private int baseW;
    private int baseH;

    private String dirStr = "./res";

    private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";
    private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";

    /**
     * {0}-HEIGHT
     */
    private final static String VALUE_TEMPLATE = "values-{0}x{1}";

    private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;800,1280;1080,1812;1080,1920;1440,2560;";

    private String supportStr = SUPPORT_DIMESION;

    public GenerateValueFiles(int baseX, int baseY, String supportStr) {
        this.baseW = baseX;
        this.baseH = baseY;

        if (!this.supportStr.contains(baseX + "," + baseY)) {
            this.supportStr += baseX + "," + baseY + ";";
        }

        this.supportStr += validateInput(supportStr);

        System.out.println(supportStr);

        File dir = new File(dirStr);
        if (!dir.exists()) {
            dir.mkdir();

        }
        System.out.println(dir.getAbsoluteFile());

    }

    /**
     * @param supportStr
     *            w,h_...w,h;
     * @return
     */
    private String validateInput(String supportStr) {
        StringBuffer sb = new StringBuffer();
        String[] vals = supportStr.split("_");
        int w = -1;
        int h = -1;
        String[] wh;
        for (String val : vals) {
            try {
                if (val == null || val.trim().length() == 0)
                    continue;

                wh = val.split(",");
                w = Integer.parseInt(wh[0]);
                h = Integer.parseInt(wh[1]);
            } catch (Exception e) {
                System.out.println("skip invalidate params : w,h = " + val);
                continue;
            }
            sb.append(w + "," + h + ";");
        }

        return sb.toString();
    }

    public void generate() {
        String[] vals = supportStr.split(";");
        for (String val : vals) {
            String[] wh = val.split(",");
            generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));
        }

    }

    private void generateXmlFile(int w, int h) {

        StringBuffer sbForWidth = new StringBuffer();
        sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sbForWidth.append("<resources>");
        float cellw = w * 1.0f / baseW;

        System.out.println("width : " + w + "," + baseW + "," + cellw);
        for (int i = 1; i < baseW; i++) {
            sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
                    change(cellw * i) + ""));
        }
        sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
                w + ""));
        sbForWidth.append("</resources>");

        StringBuffer sbForHeight = new StringBuffer();
        sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        sbForHeight.append("<resources>");
        float cellh = h *1.0f/ baseH;
        System.out.println("height : "+ h + "," + baseH + "," + cellh);
        for (int i = 1; i < baseH; i++) {
            sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",
                    change(cellh * i) + ""));
        }
        sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",
                h + ""));
        sbForHeight.append("</resources>");

        File fileDir = new File(dirStr + File.separator
                + VALUE_TEMPLATE.replace("{0}", h + "")//
                        .replace("{1}", w + ""));
        fileDir.mkdir();

        File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");
        File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");
        try {
            PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
            pw.print(sbForWidth.toString());
            pw.close();
            pw = new PrintWriter(new FileOutputStream(layyFile));
            pw.print(sbForHeight.toString());
            pw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static float change(float a) {
        int temp = (int) (a * 100);
        return temp / 100f;
    }

    public static void main(String[] args) {
        int baseW = 320;
        int baseH = 400;
        String addition = "";
        try {
            if (args.length >= 3) {
                baseW = Integer.parseInt(args[0]);
                baseH = Integer.parseInt(args[1]);
                addition = args[2];
            } else if (args.length >= 2) {
                baseW = Integer.parseInt(args[0]);
                baseH = Integer.parseInt(args[1]);
            } else if (args.length >= 1) {
                addition = args[0];
            }
        } catch (NumberFormatException e) {

            System.err
                    .println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;");
            e.printStackTrace();
            System.exit(-1);
        }

        new GenerateValueFiles(baseW, baseH, addition).generate();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166

同时我提供了jar包,默认情况下,双击即可生成,使用说明:

下载地址见文末,内置了常用的分辨率,默认基准为480*320,当然对于特殊需求,通过命令行指定即可:

例如:基准 1280 * 800 ,额外支持尺寸:1152 * 735;4500 * 3200;

按照

java -jar xx.jar width height width,height_width,height

上述格式即可。

到此,我们通过编写一个工具,根据某基准尺寸,生成所有需要适配分辨率的values文件,做到了编写布局文件时,可以参考屏幕的分辨率;在UI给出的设计图,可以快速的按照其标识的px单位进行编写布局。基本解决了适配的问题。

本方案思想已经有公司投入使用,个人认为还是很不错的,如果大家有更好的方案来解决屏幕适配的问题,欢迎留言探讨或者直接贴出好文链接,大家可以将自己的经验进行分享,这样才能壮大我们的队伍~~。

注:本方案思想来自Android Day Day Up 一群的【blue-深圳】,经其同意编写此文,上述程序也很大程度上借鉴了其分享的源码。在此标识感谢,预祝其创业成功!

===>后期更新

Google已经添加了百分比支持库,详情请看:Android 百分比布局库(percent-support-lib) 解析与扩展

ok~


下载地址


参考链接

Android多屏幕适配学习笔记

开源,原创,实用Android 屏幕适配方案分享

版权声明:本文为博主原创文章,未经博主允许不得转载。
作者:taoerit 发表于2017/11/24 11:54:15 原文链接
阅读:11 评论:0 查看评论

java.lang.NoClassDefFoundError: org/apache/hive/service/cli/thrift/TCLIService$Iface

$
0
0

今天在使用hive-jdbc连接服务器的hive时,出现了一些问题,在这里记录一下解决的方法,首先肯定要在pom中引入hive-jdbc的依赖包,然后写一段连接hive的程序,目的是获取hive中的表名和schema名称。但是运行却报错了:

java.lang.NoClassDefFoundError: org/apache/hive/service/cli/thrift/TCLIService$Iface
	at org.apache.hive.jdbc.HiveDriver.connect(HiveDriver.java:105)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:208)
	at com.bonc.vbap.data.query.jdbc.spring.datasource.DriverManagerDataSource.getConnectionFromDriverManager(DriverManagerDataSource.java:116)
	at com.bonc.vbap.data.query.jdbc.spring.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:107)
	at com.bonc.vbap.data.query.jdbc.spring.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:191)
	at com.bonc.vbap.data.query.jdbc.spring.datasource.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:161)
	at com.bonc.vbap.data.query.jdbc.ConnectionManager.getConnection(ConnectionManager.java:63)
	at com.bonc.vbap.data.schema.jdbc.JdbcSchemaContext$SchemaHelper.getConnection(JdbcSchemaContext.java:308)
	at com.bonc.vbap.data.schema.jdbc.JdbcSchemaContext$SchemaHelper.<init>(JdbcSchemaContext.java:112)
	at com.bonc.vbap.data.schema.jdbc.JdbcSchemaContext.getSchemaHelper(JdbcSchemaContext.java:68)
	at com.bonc.vbap.data.schema.jdbc.JdbcSchemaContext.getSchemaNames(JdbcSchemaContext.java:43)
	at com.bonc.vbap.data.service.impl.SchemaServiceImpl.getSchemaNames(SchemaServiceImpl.java:34)
	at com.bonc.vbap.data.schema.jdbc.TestJdbcColumn.testHiveDataQuery(TestJdbcColumn.java:252)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:52)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.ClassNotFoundException: org.apache.hive.service.cli.thrift.TCLIService$Iface
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 44 moret

提示找不到org.apache.hive.service.cli.thrift.TCLIService$Iface这个内部类,定位到..HiveDriver 105行的位置

public Connection connect(String url, Properties info) throws SQLException {
    return acceptsURL(url) ? new HiveConnection(url, info) : null;
  }
这里new 了一个HiveConnection的对象,这里并没有看到那个内部类的使用,然后发现在HiveConnection中有使用TCLIService.Iface接口

...
TCLIService.Iface client = new TCLIService.Client(new TBinaryProtocol(transport));
TOpenSessionResp openResp = client.OpenSession(new TOpenSessionReq());
  if (openResp != null) {
  client.CloseSession(new TCloseSessionReq(openResp.getSessionHandle()));
}
...
在这里抛了找不到Iface的异常,但是点进去TCLIService类中,确是存在Iface接口,所以说找不到不是因为不存在,而是有重复的类,不知道找哪个
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
@Generated(value = "Autogenerated by Thrift Compiler (0.9.3)")
public class TCLIService {

  public interface Iface {

    public TOpenSessionResp OpenSession(TOpenSessionReq req) throws org.apache.thrift.TException;

    public TCloseSessionResp CloseSession(TCloseSessionReq req) throws org.apache.thrift.TException;
.....
所以去看下引入的依赖包,发现有hive-service和hive-service-rpc两个包中有相同的源码,所以在这里会抛异常,我就先把这其中一个依赖从hive-jdbc中去除掉,但是发现还是抛异常,我这里用的hive-jdbc1.1版本,发现hive-service是2.1版本,所以立马把两个都去除掉,重新引入一个hive-service 1.1进来就好拉,完整的pom中hive的依赖:

<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-jdbc</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-service-rpc</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-service</artifactId>
    </exclusion>
  </exclusions>
  <version>1.1.0</version>
</dependency>
<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-service</artifactId>
  <version>1.1.0</version>
</dependency>
其中还有一些对元数据的依赖如果没有用到也可以去除掉:

<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-jdbc</artifactId>
  <exclusions>
    <exclusion>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-service-rpc</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-service</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-metastore</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-serde</artifactId>
    </exclusion>
  </exclusions>
  <version>1.1.0</version>
</dependency>
<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-service</artifactId>
  <version>1.1.0</version>
</dependency>
OK拉。

作者:u010429286 发表于2017/11/24 13:33:04 原文链接
阅读:15 评论:0 查看评论

自己学Docker:15.Docker使用实战--zookeeper集群部署

$
0
0

之前有介绍过使用Docker创建MySQL服务,说明了三种方式。

  1. 使用Docker镜像
  2. 通过Dockerfile构建
  3. 通过docker stack deploy(或者docker-compose)

1,2可以归为一种,即单个应用方式: Dockerfile -> 镜像 -> 容器(docker run) 。对于搭建集群环境的话,Docker Stack方式实施和管理更为方便。所以这里搭建一个zookeeper的集群环境就不再使用1,2种,想,具体方式可以参见Docker创建MySQL服务

zookeeper.yml

通过docker stack deploy方式首先要编写yaml文件。样例可以参见dockerhub的zookeeper镜像的介绍
如下:

version: '3.1'

services:
    zoo1:
        image: zookeeper
        restart: always
        hostname: zoo1
        ports:
            - 2181:2181
        environment:
            ZOO_MY_ID: 1
            ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

    zoo2:
        image: zookeeper
        restart: always
        hostname: zoo2
        ports:
            - 2182:2181
        environment:
            ZOO_MY_ID: 2
            ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

    zoo3:
        image: zookeeper
        restart: always
        hostname: zoo3
        ports:
            - 2183:2181
        environment:
            ZOO_MY_ID: 3
            ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

上面的文件创建了三个zookeeper的集群服务,以复制模式(replicated mode)启动Zookeeper,并将容器内的2181端口分别映射到主机的2181,2182,2183。

当然,严格的说,这个也不能说是集群模式。毕竟所有容器都运行再同一主机,如果宕机,所有的zookeeper服务器都将处于脱机状态。

执行,生成服务

采用如下命令:

sudo docker stack deploy -c zookeeper.yml zk

这里写图片描述

查看服务状态:

sudo docker stack services zk

这里写图片描述

连接zookeeper服务

zkCli.sh

zookeeper的bin目录下提供了一个客户端连接工具zkCli.sh。
https://www.apache.org/dyn/closer.cgi/zookeeper/下载zookeeper即可获得。
进入到bin目录下,执行命令。

./zkCli.sh -server 127.0.0.1:2181

这里写图片描述
可以成功连接到上面创建的zookeeper服务。

命令行的相关操作,可以参见
分布式服务框架ZooKeeper安装和配置
分布式服务框架ZooKeeper:四字命令

作者:Mungo 发表于2017/11/24 16:43:09 原文链接
阅读:0 评论:0 查看评论

Unity Shader 学习笔记(24) 深度纹理、法线纹理

$
0
0

Unity Shader 学习笔记(24) 深度纹理、法线纹理

参考书籍:《Unity Shader 入门精要》
3D数学 学习笔记(2) 矩阵
3D数学 学习笔记(9) 凹凸映射(bump mapping)和切线空间(tangent space)


深度纹理

即存深度值的纹理。深度值范围[0, 1]。深度值计算来源于顶点变换后得到的归一化设备坐标(Normalized Device Coordinates, NDC)。

  • 顶点从模型空间转换到齐次裁切空间:顶点着色器中,顶点乘以MVP矩阵得到。
  • 齐次裁切空间到归一化设备坐标:使用齐次除法得到。

如上图,因为最后NDC坐标范围在[-1, 1]内,要计算深度纹理像素值,需要映射到[0, 1],即:
- d = 0.5 * zndc + 0.5


获取深度纹理与法线纹理

Unity中获取深度纹理的方法:
- 直接来自深度缓存。
- 单独Pass渲染得到。即投射阴影的Pass(LightMode = “ShadowCaster”)。源码见Internal-DepthNormalsTexture.shader文件。
- 延迟渲染中访问。
- Unity使用着色器代替技术,会把RenderType为Qpauqe的物体,队列小于2500(Background、Geometry、Alphatest。不透明的队列。)的渲染到深度纹理和法线纹理中。

具体方法:
- 设置相机的纹理模式: camera.depthTextureMode = DepthTextureMode.Depth;
- 在Shdaer中声明变量_CameraDepthTexture访问:float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);

相关函数:
- LinearEyeDepth:深度采样结果转换到视角空间,即zview
- Linear01Depth:返回范围在[0, 1]的线性深度值。
- DecodeDepthNormal:对采样结果解码获取深度和法线信息。

输出线性深度值:

float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
float linearDepth = Linear01Depth(depth);
return fixed4(linearDepth, linearDepth, linearDepth, 1.0);

输出法线方向:

fixed3 normal = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, i.uv).xy);
return fixed4(normal * 0.5 + 0.5, 1);

作者:l773575310 发表于2017/11/24 16:49:57 原文链接
阅读:9 评论:0 查看评论

react native学习笔记18——存储篇(3)Realm

$
0
0

前言

Realm是一款新兴的针对移动平台设计的数据库,使用简单、跨平台、性能优越功能强大。其官网地址为:https://realm.io/。Realm与sqlite在性能上各有优势,但其更加简单易用,学习成本低。

配置

1. 安装

在项目的根目录下执行cmd命令:

npm install --save realm

2. 将项目关联realm原生模块库

react-native link realm

注意:在Android中,react-native link可能产生无效配置,例如成功更新了Gradle的配置(android/settings.gradleandroid/app/build.gradle),但没有添加Realm模块。首先确认是否成功添加Realm模块,如果没有,需要手动添加,步骤如下:

1.修改android/settings.gradle配置

...
include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')

2.修改android/app/build.gradle的配置

...

dependencies {
    ...
    compile project(':realm')
}

3.在MainApplication.java注册模块
修改android/app/src/main/java/com/[YourAppName]/MainApplication.java的配置

import io.realm.react.RealmReactPackage; // add this import

public class MainApplication extends Application implements ReactApplication {
    @Override
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new RealmReactPackage() // add this line
        );
    }
}

使用实例

下例是官网的一个最基础的实例:

import React, { Component } from 'react';
import {
    AppRegistry,
    Text,
    View,
    StyleSheet,
} from 'react-native';

const Realm = require('realm');
const DogSchema = {
    name: 'Dog',
    primaryKey:'id',
    properties: {
        id:'int',
        dogname:'string',
        color:'string',
    }
};

export default class RealmDemo extends Component {
    constructor(props) {
       super(props);
       this.state = { realm: null };
    }

    componentWillMount() {
        let realm = new Realm({schema: [DogSchema]});
        realm.write(() => {
            realm.create('Dog', {id:0,dogname: 'Rex', color:'red'});
            realm.create('Dog', {id:1,dogname: 'Jeff', color:'green'});
            realm.create('Dog', {id:2,dogname: 'Dave', color:'black'});
            //更新id为1的数据
            realm.create('Dog', {id:1, color:'white'},true);
        });
        this.setState({realm});
    }

    render() {
    const info = this.state.realm
    ? 'Number of dogs in this Realm: ' + this.state.realm.objects('Dog').length
    : 'Loading...';

    return (
        <View style={styles.container}>
        <Text >
        {info}
        </Text>
        </View>
    );
}
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#f2f2f2',
        paddingTop:20,
    },
});

新建表模型

在进行数据库的增删改查之前,首先得创建数据库表。
该实例中用Realm新建一个名为Dog的表。表模型的设计如下:

//新建表模型
const DogSchema = {
    name: 'Dog',
    primaryKey:'id',
    properties: {
        id:'int',
        dogname:'string',
        color:'string',
    }
};
  • name: 表名字。
  • primaryKey: 主键,可以是 ‘int’ 或’string’,主键必须保持唯一性,一旦将某字段设定为主键后该表的主键无法变更。
  • properties: 该属性内设置自定义的表字段名。如上例中properties: {dogname: 'string'}dogname为字段名,string为类型。

建表

//建表
let realm = new Realm({schema: [DogSchema]});

也可同时创建多个表,如:

let realm = new Realm({schema: [DogSchema,CatSchema,PersonSchema]});

Realm支持以下的一些基础类型:bool,int,float,double,string,data和date。

  • bool属性映射到JavaScript中Boolean对象
  • int,float和double属性映射到JavaScript中Number对象,不过’int’和’double’会以64位进行存储但是float会以32位进行存储
  • string属性会被映射成String对象
  • data属性会被映射成ArrayBuffer对象
  • date属性会被映射成Date对象
    当需要对属性进行设置类型的时候,一般直接写属性类型就行,不需要使用一个字典格式的写法,虽然下面两种写法是等价的。
const DogSchema = {
  name: 'Car',
  properties: {
    // The following property types are equivalent
    dogname:   {type: 'string'},
    color: 'string',
  }
}

插入数据

realm.write(() => {
    realm.create('Dog', {id:0,dogname: 'Rex', color:'red'});
    realm.create('Dog', {id:1,dogname: 'Jeff', color:'green'});
    realm.create('Dog', {id:2,dogname: 'Dave', color:'black'});
});

查询数据

  • 查询所有数据
    可通过realm.objects(“name”)的方式获取该数据表所有的数据。
let dogs = realm.objects('Dog');
console.log ('name:' + dogs[0].dogname);
  • 根据条件查询数据
    可通过filtered方法对查询到的所有数据进行筛选,如下:
  let dogs = realm.objects('Dog');
  let redDogs = dogs.filtered('color = "red" AND name BEGINSWITH "B"');

当前Realm仅支持部分NSPredicate语法进行查询语句的筛选:对数字类型的数据支持基本的比较操作:==,!=, >,>=, <, 和 <=
。对string类型支持:==, BEGINSWITH, ENDSWITH, CONTAINS。string类型数据可以不分大小写通过==[c],BEGINSWITH[c]等等比较过滤。同样比较的时候可以通过获取对象的属性获取数据进行比较例如car.color=='blue'
目前的Realm版本(Realm Javascript 2.0.4)仅支持Realm类型数据的列表的筛选,以后可能会支持基本类型数据的列表筛选。

更新数据

如果构建的表模型中含有主键primaryKey,可以利用realm.create方法根据primaryKey修改对应的数据的值,并在第三个参数传入true。

realm.create('Dog', {id:1, color:'white'},true);

在上例中由于我们已经存在了id为1的数据,并且第三个参数传入了true,因此color属性会被更新为white值而不是新增一条数据。

删除数据

realm.write(() => {
  // Create a dog object
  let dog = realm.create('Dog', {id:0,dogname: 'Rex', color:'red'});

  //删除单个数据
  // Delete the dog
  realm.delete(dog);

  //删除所有数据
  // Delete multiple dogs by passing in a `Results`, `List` or JavaScript `Array`
  let allDogs = realm.objects('Dog');
  realm.delete(allDogs); // Deletes all dogs
});

自动更新的特性

查询Realm返回的列表对象,对列表数据更新会自动保存在底层Realm中,这也意味着我们没有必要去重新查询数据库获取数据,修改列表对象会立即影响到查询的结果。

let night = realm.objects('Dog').filtered('dogname = "Night"');
// night.length == 0
realm.write(() => {
  realm.create('Dog', {id:3,dogname: 'Night', color:'red'});
});
// night.length == 1

上例中首先查询dogname为Night的狗,返回结果为0(因为我们根本就没添加),然后插入一条dogname为Night的数据,而此时并没有重新查询该表,但查询结果中已经有了一条数据了。

以上是realm的基本数据操作方法,如需更深入的了解,可以查看官方文档

作者:teagreen_red 发表于2017/11/24 16:52:09 原文链接
阅读:2 评论:0 查看评论

leetcode-728. Self Dividing Numbers

$
0
0

728. Self Dividing Numbers

self-dividing number is a number that is divisible by every digit it contains.

For example, 128 is a self-dividing number because 128 % 1 == 0128 % 2 == 0, and 128 % 8 == 0.

Also, a self-dividing number is not allowed to contain the digit zero.

Given a lower and upper number bound, output a list of every possible self dividing number, including the bounds if possible.

Example 1:

Input: 
left = 1, right = 22
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]

Note:

  • The boundaries of each input argument are 1 <= left <= right <= 10000.


    题意:

    输出 left,right 之间的数,要求是能够被自己的所有位的数整除。


    只要一直除自己的每一位的数就可以了,用循环取整和取余就可以得到所有的位数。

    自己一开始只想着用String转换,然后用了很多库函数,,果然超时了。。

    改为循环就快了很多。。


    AC代码:

    class Solution {
        public List<Integer> selfDividingNumbers(int left, int right) {
            List<Integer> list = new ArrayList<>();
            for (int i = left;i<=right ;i++ ) {
                int j = i;
                for (;j > 0 ;j= j/10 ) {
                    if( (j%10==0 )|| (i%(j%10))!=0) break;
                }
                if(j==0) list.add(i);
            }
            return list;
        }
    }



    自己一开始写的:(辣眼睛,未AC)

    class Solution {
        public List<Integer> selfDividingNumbers(int left, int right) {
            List<Integer> list = new ArrayList<>();
    		for (int i = left;i <= right ;i++ ) {
    			String temp = String.valueOf(i);
    			int flag = 0;
    			for (int j = 0; j<temp.length() ;i++ ) {
    				if(i % Integer.valueOf(String.valueOf(temp.charAt(j))) != 0){
    					flag = 1;
    					break;
    				}
    			}
    			if(flag == 0){
    				list.add(i);
    			}
    		}
    		return list;
        }
    }



  • 作者:qq_32832023 发表于2017/11/24 16:57:14 原文链接
    阅读:0 评论:0 查看评论

    关于Harbor上镜像删除

    $
    0
    0

    参考:https://github.com/vmware/harbor/blob/master/docs/user_guide.md

    关于Harbor上容器镜像的删除,有如下的介绍:
    这里写图片描述

    可以简单概括为:

    Harbor的UI界面上先删除镜像,但这个操作并没有删除磁盘上存放的镜像文件,只是镜像文件manifest的映射关系,还需要通过GC来删除。

    先停止Harbor:

    docker-compose stop

    通过带有–dry-run选项,可以查看到将要删除的镜像文件:

    docker run -it --name gc --rm --volumes-from registry vmware/registry:2.6.2-photon garbage-collect --dry-run /etc/registry/config.yml

    不带–dry-run选项,直接执行删除:

    docker run -it --name gc --rm --volumes-from registry vmware/registry:2.6.2-photon garbage-collect /etc/registry/config.yml

    再启动Harbor:

    docker-compose start

    从上面可以知道,如果要定期的删除大量的镜像还是很麻烦的。目前还没有发现Harbor有可调用的Rest API来实现镜像的删除,如果有就更方便了。

    作者:felix_yujing 发表于2017/11/24 17:48:48 原文链接
    阅读:28 评论:0 查看评论

    AsyncTask源码解析

    $
    0
    0

    转载请标明出处:【顾林海的博客】

    前言

    AsyncTask是一种轻量级的异步任务类,内部封装了Thread和Handler,通过AsyncTask执行后台任务以及在主线程中访问UI控件,但AsyncTask在Android 1.6之前是串行任务,在Android 1.6时AsyncTask采用线程池处理并行任务,又在Android 3.0开始采用一个线程串行执行任务,所以在使用AsyncTask时需要根据具体的场景来选择是否使用AsyncTask,比如需要与主线程有交互可以使用AsyncTask,否则就使用线程,如果需要执行大量线程执行任务时推荐使用线程池,AsyncTask的使用方式并不会讲解,这个大家可以在网上随便搜搜,文章主要围绕AsyncTask的源码来解析执行的流程。

    源码解析

    在使用AsyncTask时,需要重写它的几个方法,其中doInBackground(Params… params)方法必须实现,该方法用于执行异步任务,参数params表示异步任务的输入参数,在这个方法中可以通过publishProgress方法来更新任务进度,publishProgress方法会调用onProgressUpdate方法,改方法在主线程中执行;如果需要在执行异步之前做一些初始化操作,比如显示一个进度条,可以重写它的onPreExecute方法,这个方法执行在主线程;当doInBackground方法执行完毕,如果需要异步任务数据返回给主线程,可以重写onPostExecute(Result result)方法,这个方法在主线程中执行,参数result是后台返回的值,也就是doInBackground方法返回的值,那么AsyncTask整体执行的流程可以用下面的图来表示。

    这里写图片描述

    执行AsyncTask的方法是execute,贴出其中一个execute方法源码:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    在执行AsyncTask的execute(Params… params)方法时,内部会去执行executeOnExecutor方法,其中的参数sDefaultExecutor是AsyncTask内部类SerialExecutor的实例,是一个串行的线程池,SerialExecutor实现Executor接口并实现Executor接口中的execute(Runnable command)方法,用于执行已经提交的Runnable任务对象,SerialExecutor这个内部类的具体实现可以通过下面的源码来得知。

    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
    
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
    
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    
    
    public static final Executor THREAD_POOL_EXECUTOR;
    
    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

    SerialExecutor类中定义了一个ArrayDeque,它是一个先进先出的队列,在execute方法中通过scheduleNext方法从队列中取出Runnable对象,并通过THREAD_POOL_EXECUTOR来执行,THREAD_POOL_EXECUTOR是线程池。上面的SerialExecutor是用于任务的排队,而线程池THREAD_POOL_EXECUTOR才是执行任务的,关于SerialExecutor的介绍暂时就到这里,我们会到上面的execute方法。

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }
    
        mStatus = Status.RUNNING;
    
        onPreExecute();
    
        mWorker.mParams = params;
        exec.execute(mFuture);
    
        return this;
    }

    通过execute(Params… params)方法执行executeOnExecutor(Executor exec,Params… params)方法,在一开始会对当前的执行的状态进行判断,Status是一个枚举类,内部提供了三种状态,分别是FENDING(表示尚未执行)、RUNNING(表示任务正在执行)和FINISHED(表示任务执行结束),AsyncTask内部在执行任务前会去判断当前任务的执行状态,当任务正在执行或是已经执行结束会抛出异常,当新任务开始时mStatus为RUNNING,表示开始执行异步任务,接着会调用onPreExecute()方法,这时还没有执行异步任务,所以onPreExecute方法在主线程中执行。
    onPreExecute方法执行完毕后,会将我们传入的Params参数封装成FutureTask对象,其中的mWorker是内部静态类WorkerRunnable,源码如下。

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

    WorkerRunnable实现了Callable接口,用于获取异步任务执行完毕后的数据,上面的mWorker和mFuture在AsyncTask初始化时进行初始化,看下面的源码。

    public AsyncTask() {
        this((Looper) null);
    }
    
    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()//--------------1
            : new Handler(callbackLooper);
    
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);//————2
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };
    
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

    上面1处代码判断callbackLooper是否空或是主线程的Looper,这个因为传入的是null,最终调用的是getMainHandler方法,用于创建Handler,这部分后面会讲到,继续看mWorker的实例化时实现了call方法,并返回异步任务执行结果Result,这里又看到一个熟悉的方法doInBackground方法,这个方法执行在异步线程中,mFuture在实例化时将mWorker作为参数并实现了done方法,可以看到内部通过get()方法获取mWorker的call方法的返回值,并传递给postResultlfNotInvoked方法,这里看下它的源码。

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

    mTaskInvoked是AtomicBoolean类型,在上面执行mWorker的call方法时(代码2处)mTaskInvoked设置为true,因此这里的判断语句不成立,就不继续往下看了,回到上面的mWorker初始化的地方,这里为了大家方便查看,再次把相关源码贴下:

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };

    在执行完doInBackground方法后会返回Result,最后会执行finally语句块中的postResult方法,查看该方法源码:

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

    很明显通过Handler来发送消息,找找Handler的定义的地方,还记得我们在上面介绍AsyncTask初始化时讲到传入的参数callbackLooper为空,就调用getMainHandler方法,也就是说这里的发送消息的Handler就是在getMainHandler方法中初始化的,查看getMainHandler方法源码。

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

    InternalHandler是AsyncTask的内部静态类并继承自Handler。

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
    
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

    之前在doInBackground方法执行完毕后会将Result和MESSAGE_POST_RESULT通过Handler发送给主线程,在handleMessage方法中将我们的Result包装成AsyncTaskResult类型,AsyncTaskResult内部有个Data范型数组,数组的第一个就是异步任务执行的结果,这里将结果传递给finish方法。

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

    在这里又看到一个熟悉的方法onPostExecute方法,这个方法是执行在主线程中的用于与UI交互,执行完onPostExecute方法后会将mStatus设置为FINISHED,说明此次异步任务执行完毕。到这里onPreExecute、doInBackground和onPostExecute方法执行时机都已经讲解清楚了,剩下的就是onProgressUpdate方法的执行时机,从前面知道在doInBackground方法中执行publishProgress方法会执行onProgressUpdate方法,查看publishProgress方法源码。

    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

    在这里也是通过Handler来发送消息给主线程来执行onProgressUpdate方法。

    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
    
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

    发送消息到主线程后会执行onProgressUpdate方法,这也说明了onProgressUpdate是执行在主线程中。

    在这里提一下,之前在前言中讲过由于Android版本的不同,AsyncTask内部执行的机制也不同,这里AsyncTask新增了一个方法executeOnExecutor(Executor exec,Params… params)用于开发者自己定义线程池。

    作者:GULINHAI12 发表于2017/11/24 19:14:21 原文链接
    阅读:24 评论:0 查看评论

    MyBatis的collection集合封装规则

    $
    0
    0

    MyBatis的collection集合封装规则



    DepartmentMapper.java

    package com.cn.mybatis.dao;
    
    import java.util.List;
    import java.util.Map;
    
    
    import org.apache.ibatis.annotations.MapKey;
    import org.apache.ibatis.annotations.Param;
    
    import com.cn.zhu.bean.Department;
    import com.cn.zhu.bean.Employee;
    
    public interface DepartmentMapper {
    	public Department getDeptById(Integer id);
    	public Department getDeptByIdPlus(Integer id);
    	
    	public Department getDeptByIdStep(Integer id);
    	public List<Employee> getEmpsByDeptId(Integer deptId);
     }
       
    EmployeeMapperPlus.java

    package com.cn.mybatis.dao;
    
    import java.util.List;
    import java.util.Map;
    
    
    import org.apache.ibatis.annotations.MapKey;
    import org.apache.ibatis.annotations.Param;
    
    import com.cn.zhu.bean.Employee;
    
    public interface EmployeeMapperPlus {
    	public Employee getEmpById(Integer id);
    	public Employee getEmpAndDept(Integer id);
    	public Employee getEmpByIdStep(Integer id);
     }
    
    Department.java

    package com.cn.zhu.bean;
    
    import java.util.List;
    
    public class Department {
    	private 	Integer  id;
    	private  String  departmentName;
    	private List<Employee> emps;
    	
    	
    	
    	public List<Employee> getEmps() {
    		return emps;
    	}
    	public void setEmps(List<Employee> emps) {
    		this.emps = emps;
    	}
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getDepartmentName() {
    		return departmentName;
    	}
    	public void setDepartmentName(String departmentName) {
    		this.departmentName = departmentName;
    	}
    	@Override
    	public String toString() {
    		return "Department [departmentName=" + departmentName + ", id=" + id
    				+ "]";
    	}
    	
    }
    

    DepartmentMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cn.mybatis.dao.DepartmentMapper">
    	<!-- public Department getDeptById(Integer id); -->
    	<select id="getDeptById" resultType="com.cn.zhu.bean.Department">
    		select id,dept_name
    		departmentName from tbl_dept where id=#{id}
        </select>
        
        
    	<!-- public Department getDeptByIdPlus(Integer id); -->
    	<!-- 嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 -->
    	<resultMap type="com.cn.zhu.bean.Department" id="MyDept">
    		<id column="did" property="id" />
    		<result column="dept_name" property="departmentName" />
    		<!--
    			collection 定义关联集合类型的属性的封装 ofType 指定集合里面元素的类型
    		-->
    		<collection property="emps" ofType="com.cn.zhu.bean.Employee">
    			<!-- 定义这个集合元素的封装规则 -->
    			<id column="eid" property="id" />
    			<result column="last_name" property="lastName" />
    			<result column="email" property="email" />
    			<result column="gender" property="gender" />
    		</collection>
    	</resultMap>
    	<select id="getDeptByIdPlus" resultMap="MyDept">
    		SELECT d.id
    		did,d.dept_name dept_name,
    		e.id eid,e.last_name last_name,
    		e.email
    		email,e.gender gender
    		FROM tbl_dept d LEFT JOIN tbl_employee e
    		on
    		d.id=e.d_id
    		where d.id=#{id}
        </select>
    
    	
    	<!--  扩展,多列的值传递过去 
                  将多列的值封装map传递
                  column="{key1=column,key2=column2}"
                  fetchType="lazy" : 表示使用延迟加载
                      lazy 延迟
                      eager 立即加载
        -->
    
    </mapper>

    mybatis-config.xml

    	<mappers>
    		<mapper resource="mybatis/mapper/EmployeeMapperPlus.xml" />
    		<mapper resource="mybatis/mapper/DepartmentMapper.xml" />
    	</mappers>

    测试方法:

    @Test
    	public void test06() throws IOException{
    		SqlSessionFactory sqlsessionFactory=getSqlSessionFactory();
    		// 1  获取到的sqlsession不会自动提交数据
    		SqlSession openSession=sqlsessionFactory.openSession();
    
    		try{
    
    			DepartmentMapper mapper=openSession.getMapper(DepartmentMapper.class);
    			//级联查询 
    			Department   employee=mapper.getDeptByIdPlus(1);
    			System.out.println(employee);
    			System.out.println(employee.getEmps());
    			
    
    		}finally{
    			openSession.commit();
    		}
    	}


    接下来会写collection的分段查询

    作者:zhupengqq 发表于2017/11/24 19:34:50 原文链接
    阅读:1 评论:0 查看评论

    MyBatis的collection集合的分布查询

    $
    0
    0

     MyBatis的collection集合的分布查询


    DepartmentMapper.java

    package com.cn.mybatis.dao;
    
    import java.util.List;
    import java.util.Map;
    
    
    import org.apache.ibatis.annotations.MapKey;
    import org.apache.ibatis.annotations.Param;
    
    import com.cn.zhu.bean.Department;
    import com.cn.zhu.bean.Employee;
    
    public interface DepartmentMapper {
    	public Department getDeptById(Integer id);
    	public Department getDeptByIdPlus(Integer id);
    	
    	public Department getDeptByIdStep(Integer id);
    	public List<Employee> getEmpsByDeptId(Integer deptId);
     }
       


    EmployeeMapperPlus.java

    [java] view plain copy
    1. package com.cn.mybatis.dao;  
    2.   
    3. import java.util.List;  
    4. import java.util.Map;  
    5.   
    6.   
    7. import org.apache.ibatis.annotations.MapKey;  
    8. import org.apache.ibatis.annotations.Param;  
    9.   
    10. import com.cn.zhu.bean.Employee;  
    11.   
    12. public interface EmployeeMapperPlus {  
    13.     public Employee getEmpById(Integer id);  
    14.     public Employee getEmpAndDept(Integer id);  
    15.     public Employee getEmpByIdStep(Integer id);  
    16.  }  
    Department.java

    [java] view plain copy
    1. package com.cn.zhu.bean;  
    2.   
    3. import java.util.List;  
    4.   
    5. public class Department {  
    6.     private     Integer  id;  
    7.     private  String  departmentName;  
    8.     private List<Employee> emps;  
    9.       
    10.       
    11.       
    12.     public List<Employee> getEmps() {  
    13.         return emps;  
    14.     }  
    15.     public void setEmps(List<Employee> emps) {  
    16.         this.emps = emps;  
    17.     }  
    18.     public Integer getId() {  
    19.         return id;  
    20.     }  
    21.     public void setId(Integer id) {  
    22.         this.id = id;  
    23.     }  
    24.     public String getDepartmentName() {  
    25.         return departmentName;  
    26.     }  
    27.     public void setDepartmentName(String departmentName) {  
    28.         this.departmentName = departmentName;  
    29.     }  
    30.     @Override  
    31.     public String toString() {  
    32.         return "Department [departmentName=" + departmentName + ", id=" + id  
    33.                 + "]";  
    34.     }  
    35.       
    36. }  

    DepartmentMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cn.mybatis.dao.DepartmentMapper">
    	<!-- public Department getDeptById(Integer id); -->
    	<select id="getDeptById" resultType="com.cn.zhu.bean.Department">
    		select id,dept_name
    		departmentName from tbl_dept where id=#{id}
        </select>
        
        
    	
    	<!-- collection集合分段查询 -->
    	<resultMap type="com.cn.zhu.bean.Department" id="MyDeptStept">
    		<id column="id" property="id" />
    		<result column="dept_name" property="departmentName" />
    		<collection property="emps"
    			select="com.cn.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
    			column="{deptId=id}">
    		</collection>
    	</resultMap>
    	<!-- public Department getDeptByIdStep(Integer id); -->
    	<select id="getDeptByIdStep" resultMap="MyDeptStept">
    		select id,dept_name departmentName from tbl_dept where id=#{id}
        </select>
    	<!--  扩展,多列的值传递过去 
                  将多列的值封装map传递
                  column="{key1=column,key2=column2}"
                  fetchType="lazy" : 表示使用延迟加载
                      lazy 延迟
                      eager 立即加载
        -->
    
    </mapper>

    EmployeeMapperPlus.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cn.mybatis.dao.EmployeeMapperPlus">
    
    	
     	<!-- 分布好处  可以使用延迟加载
     	     Employee==>Dept
     	          我们每次查询Employee对象的时候,都将一起查询出来。
     	          部门信息在我们使用的时候再去查询
     	          分段查询的基础之上加上两个配置
     	 -->
     	 
     	 <!-- 
     	       查询二
     	      查询部门的时候将部门对应的所有员工信息也查询出来
     	    	public List<Employee> getEmpsByDeptId(Integer deptId);
     	  -->
     	  <select resultType="com.cn.zhu.bean.Employee" id="getEmpsByDeptId">
     	     select * from tbl_employee where d_id=#{deptId}
     	  </select>
    </mapper>



    mybatis-config.xml

    [html] view plain copy
    1. <mappers>  
    2.     <mapper resource="mybatis/mapper/EmployeeMapperPlus.xml" />  
    3.     <mapper resource="mybatis/mapper/DepartmentMapper.xml" />  
    4. </mappers>  


    作者:zhupengqq 发表于2017/11/24 19:43:16 原文链接
    阅读:2 评论:0 查看评论

    Xposed框架初次见面

    $
    0
    0

    Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的虚拟机的劫持。基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作.与 iOS 越狱后的插件相似。由于涉及到修改系统,所以如果调教不当,很可能会使你的手机变成砖

    作者:Fighting_Boss 发表于2017/11/24 19:49:55 原文链接
    阅读:13 评论:0 查看评论

    33.开源项目--git分支与本地分支的区别

    $
    0
    0

    远程分支与本地分支的
    步骤一:git fetch
    步骤二:git rebase origin/master(合并远程分支master)

    这里写图片描述

    步骤三:git push origin master(本地同步到远程)

    这里写图片描述

    步骤四:使用git fetch(同步远端)

    这里写图片描述

    本地和远程的hash一致

    这里写图片描述
    这里写图片描述

    作者:aixiaoxiaoyu 发表于2017/11/24 21:06:19 原文链接
    阅读:28 评论:0 查看评论

    34.开源项目--git添加新的远程版本库

    $
    0
    0

    1.添加新的远程版本库

    这里写图片描述

    这里写图片描述

    2.同步远程分支

    这里写图片描述

    3.创建分支

    这里写图片描述

    备注:
    1. git branch dd-merge daydayman/merge
    dd-merge(创建分支名称)
    daydayman/merge(创建分支中的那一个)

    作者:aixiaoxiaoyu 发表于2017/11/24 21:11:48 原文链接
    阅读:29 评论:0 查看评论

    34.开源项目--git标签的基本概念

    $
    0
    0

    1.标签存放的地方
    这里写图片描述

    这里写图片描述

    1.创建标签

    这里写图片描述

    2.查看标签

    这里写图片描述

    3.推送标签到远端
    git push orgin v1.0
    这里写图片描述

    作者:aixiaoxiaoyu 发表于2017/11/24 21:19:16 原文链接
    阅读:30 评论:0 查看评论

    Presto内存管理源码分析

    $
    0
    0

    1. 内存池初始化

    初始化代码在LocalMemoryManager中,启动时将内存分为3个内存池,分别是:

    • RESERVED_POOL:预留内存池,用于执行最耗费内存资源的查询。
    • GENERAL_POOL:普通内存池,用于执行除最耗费内存查询以外的查询。
    • SYSTEM_POOL:系统内存池,预留的用于Presto内部数据结构和临时的分配需求使用的内存。
    long maxHeap = Runtime.getRuntime().maxMemory();
    //堆内存最大值,由Xmx指定
    maxMemory = new DataSize(maxHeap - systemMemoryConfig.getReservedSystemMemory().toBytes(), BYTE);
    //扣除系统内存池的剩余最大内存
    builder.put(RESERVED_POOL, new MemoryPool(RESERVED_POOL, config.getMaxQueryMemoryPerNode()));
    //RESERVED_POOL的大小由MaxQueryMemoryPerNode指定
    DataSize generalPoolSize = new DataSize(Math.max(0, maxMemory.toBytes() - config.getMaxQueryMemoryPerNode().toBytes()), BYTE);
    builder.put(GENERAL_POOL, new MemoryPool(GENERAL_POOL, generalPoolSize));
    //扣除SYSTEM_POOL,再扣除RESERVED_POOL,剩余内存作为GENERAL_POOL
    builder.put(SYSTEM_POOL, new MemoryPool(SYSTEM_POOL, systemMemoryConfig.getReservedSystemMemory()));

    2. 定时调整内存池分配策略

    首先看SqlQueryManager的代码

    queryManagementExecutor.scheduleWithFixedDelay(() -> {
        ...
        enforceMemoryLimits();
        ...
    }, 1, 1, TimeUnit.SECONDS); //每隔1S触发一次

    其调用的是ClusterMemoryManager的process方法,其中有一行:

    updateNodes(updateAssignments(queries));

    我们看updateAssignments方法,其作用是找出最耗费内存的查询,并放入RESERVED_POOL:

    if (reservedPool.getAssignedQueries() == 0 && generalPool.getBlockedNodes() > 0) {
    //要求reservedPool当前没有分配查询,并且generalPool中有阻塞的节点
        QueryExecution biggestQuery = null;
        long maxMemory = -1;
    
        for (QueryExecution queryExecution : queries) {
            if (resourceOvercommit(queryExecution.getSession())) {
                // 不要提升那些请求资源过量使用的查询到reserved pool,因为他们的内存使用是没有限制的。
                continue;
            }
            long bytesUsed = queryExecution.getTotalMemoryReservation();
            if (bytesUsed > maxMemory) {
                biggestQuery = queryExecution;
                maxMemory = bytesUsed;
            }
        }
        if (biggestQuery != null) {
            biggestQuery.setMemoryPool(new VersionedMemoryPoolId(RESERVED_POOL, version));
        }
    }

    再看外层的updateNodes方法,可以发现RESERVED POOL的这种分配策略会应用到每个节点。也就是说这个查询在每个节点都会独占RESERVED POOL的空间。

    // Schedule refresh
    for (RemoteNodeMemory node : nodes.values()) {
        node.asyncRefresh(assignments);
    }

    3. 配置优化

    以下是调整前的Presto的配置

    query.max-memory=14GB
    query.max-memory-per-node=7GB
    resources.reserved-system-memory=2GB
    -Xmx10G

    计算可得:

    • 节点总内存:10GB
    • RESERVED_POOL(预留内存池):7GB
    • GENERAL_POOL(普通内存池):1GB
    • SYSTEM_POOL(系统内存池):2GB

    分析:

    • 实际执行查询发现SYSTEM_POOL最大使用量大概在1.3GB,基本符合要求。
    • 当只提交一个查询时,该查询会进入GENERAL POOL,并出现了可用量为负数的情况(即可用量已无法完成查询),而此时RESERVED POOL的可用量却为7GB,一点都没使用。
    • 可以得出目前RESERVED_POOL设置的不太合理,可改为2GB。

    保持总内存不变进行修改,修改后配置:

    query.max-memory=14GB
    query.max-memory-per-node=2GB
    resources.reserved-system-memory=2GB
    -Xmx10G

    经测试,该配置可以较好的利用资源。

    作者:Lnho2015 发表于2017/11/24 21:21:00 原文链接
    阅读:49 评论:0 查看评论

    35.开源项目--git发起一个公开项目

    36.开源项目--git搭建本地Git服务器

    $
    0
    0

    这里写图片描述

    架设自己的git服务器

    这里写图片描述

    访问权限

    这里写图片描述

    创建服务器端的git
    步骤一:把远程仓库下载

    git clone chensiyu@192.168.48.131:/home/chensiyu/Desktop/hello.git
    步骤二:修改文件
    步骤三:推送到服务器
    git push origin master:master

    这里写图片描述

    这里写图片描述
    步骤四:安装

    apt-get install lighttpd

    步骤五:运行

    git instaweb

    步骤六 :gitk可以查看版本

    备注:完整的版本库## 标题 ##

    作者:aixiaoxiaoyu 发表于2017/11/24 21:33:07 原文链接
    阅读:26 评论:0 查看评论

    37.开源项目--git+repo+gerrit环境介绍

    Viewing all 35570 articles
    Browse latest View live


    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>