很久没用过Python了,熟悉一下用法准备ms。
1 | input('input:') var= |
暂时理解input()读入一行数据,且可以加入提示信息。
读入一个整数:
1 | s = input('birth: ') |
# 注释某行中其后的内容。
缩进代替C系列语言中的大括号。
大小写敏感。
字符串可用''或""包裹, \可用于转义。\n\t等
r’’表示’’内部的字符串默认不转义
'''表示多行输入
1 | print(r'\\\t\\') |
空值是一个特殊的值,用None表示。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。
用全部大写的变量名表示常量。
三种除法,//地板除,/整除,得到浮点数,%取余。
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符。
格式化:
1 | 'Hi, %s, you have $%d.' % ('Michael', 1000000) |
1 | 1] fruits[- |
不可更改的list,声明用()
当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来。
t = (1)定义的是自然数1,要定义成tuple需要加‘,’,规则。
t = (‘a’, ‘b’, [‘A’, ‘B’])其中的list是可变的。
1 | 'Michael': 95, 'Bob': 75, 'Tracy': 85} d = { |
1 | 'Thomas' in d |
1 | s = set([1, 2, 3]) |
可以对集合进行&和|操作。
1 | age = 3 |
可打印list、tuple中的数据。
1 | names = ['Michael', 'Bob', 'Tracy'] |
1 | sum = 0 |
同C系列语言
1 | abs # 变量a指向abs函数 a = |
1 | def my_abs(x): |
默认参数
1 | def power(x, n=2): |
可变参数
1 | def calc(*numbers): |
*nums表示把nums这个list的所有元素作为可变参数传进去。
关键字参数
1 | def person(name, age, **kw): |
**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra
命名关键字参数
1 | def person(name, age, *, city, job): |
参数组合
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
支持递归
1 | L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] |
1 | 'a': 1, 'b': 2, 'c': 3} d = { |
1 | for x in range(1, 11)] [x * x |
1 | def fib(max): |
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Python的for循环本质上就是通过不断调用next()函数实现的,例如:
1 | for x in [1, 2, 3, 4, 5]: |
1 | def add(x, y, f): |
1 | def f(x): |
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
1 | from functools import reduce |
1 | def is_odd(n): |
1 | sorted([36, 5, -12, 9, -21], key=abs) |
遇到了挺多的问题,但是每个问题都写篇文章感觉有点不实在,所以还是选择将这些小知识点都汇集到这一篇文章,方便自己再次查看吧。好多问题解决了之后没有及时记录下来,现在忘得差不多了。
这个问题遇到过好几次了,但是还是没有很快地解决它.不过最终还是解决了~所以还是记下来踩过的坑吧
代码如下. 在我们看来这可能是再平常不过的代码了,但是它就是报错了,而且就是在replace
这个函数这里. 它需要的就是一个Fragment
呀,我的fragment
也是一个继承了Fragment
类, 为什么就不能完成类型匹配呢? 所以很是纠结
1 | getFragmentManager().beginTransaction() |
但是,我心里清楚,我的fragment是继承自android.support.v4.app.Fragment
, 而且我还记得之前使用过一个叫做getSupportFragmentManager()
的方法, 但是为什么在这个Activity
里面就是调用不出来! 气愤啊, 但是想到了一个叫做AppCompatActivity
的适用性高的类, 因此只能想到是不是只有support类型的Activity
才有getSupportFragmentManager()
. 让宿主Activity
继承AppCompatActivity
, 最后调用出了getSupportFragmentManager()
, 解决了这个莫名其妙的问题!
FragmentManager
也有两种, 一个是android.support.v4.app
包下的,一个是android.app
包下的.Activity
的活动里面,只能获取到android.app.FragmentManager
; 继承自AppCompatActivity
才可以获得android.support.v4.app.FragmentManager
FragmentManager
只能替换继承自同一个包下面的Fragment
.Calendar
中获取到的月份比实际月份少1不算是bug吧。就像数组一样,月份也从0开始算。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 /**
* Field number for <code>get</code> and <code>set</code> indicating the
* month. This is a calendar-specific value. The first month of
* the year in the Gregorian and Julian calendars is
* <code>JANUARY</code> which is 0; the last depends on the number
* of months in a year.
*
* @see #JANUARY
* @see #FEBRUARY
* @see #MARCH
* @see #APRIL
* @see #MAY
* @see #JUNE
* @see #JULY
* @see #AUGUST
* @see #SEPTEMBER
* @see #OCTOBER
* @see #NOVEMBER
* @see #DECEMBER
* @see #UNDECIMBER
*/
SQLiteLog: (1) no such table
其实这个问题的出现,是对SQLiteOpenHelper
没有了解清楚的一种表现。这段回答确实是醍醐灌顶。
SQLiteOpenHelper
onCreate()
andonUpgrade()
callbacks are invoked when the database is actually opened, for example by a call togetWritableDatabase()
. The database is not opened when the database helper object itself is created.
SQLiteOpenHelper
versions the database files. The version number is theint
argument passed to the constructor. In the database file, the version number is stored inPRAGMA user_version
.
onCreate()
is only run when the database file did not exist and was just created. IfonCreate()
returns successfully (doesn’t throw an exception), the database is assumed to be created with the requested version number. As an implication, you should not catchSQLException
s inonCreate()
yourself.
onUpgrade()
is only called when the database file exists but the stored version number is lower than requested in constructor. TheonUpgrade()
should update the table schema to the requested version.When changing the table schema in code (
onCreate()
), you should make sure the database is updated. Two main approaches:
- Delete the old database file so that
onCreate()
is run again. This is often preferred at development time where you have control over the installed versions and data loss is not an issue. Some ways to to delete the database file:
- Uninstall the application. Use the application manager or
adb uninstall your.package.name
from shell.- Clear application data. Use the application manager.
- Increment the database version so that
onUpgrade()
is invoked. This is slightly more complicated as more code is needed.
- For development time schema upgrades where data loss is not an issue, you can just use
execSQL("DROP TABLE IF EXISTS <tablename>")
in to remove your existing tables and callonCreate()
to recreate the database.- For released versions, you should implement data migration in
onUpgrade()
so your users don’t lose their data.
出现这样的错误的情景为:
有两张表,开始的时候创建了一个**Helper
继承自SQLiteOpenHelper
,然后又需要创建一张表的时候,又创建了一个类继承自SQLiteOpenHelper
,里面的数据库名相同,版本号相同,只有表名、创建的SQL语句不同。这样做的原因是因为以为每次都会执行onCreate()
,然后表就被创建了。这样的想法是错误的,根本就不是这么一回事。没有好好看过数据库相关的啊~
在没看到这个回答之前,有过两次尝试,都解决了问题,但是为什么解决了,我竟然不知道!!
尝试一:把两个数据库名改成不同的。这样就会在/data/data/**/databases/
下面存在两个数据库文件。解决了问题。
尝试二:后来感觉可能与数据库的版本有关系,所以这次不改数据库名,但是将后者的版本号提高,并重载onDowngrade()
方法,让它不干任何事情。
最终方案:将两个继承自SQLiteOpenHelper
的类全部写到一个类里面,将另外一个删除掉。我觉得这是比较完美的解决方案,也大致明白了这背后的原因。好好地又上了一课。如下所示:
WebView
显示中文网页乱码很久之前也遇到过这个问题,但是到现在记得的也就是可以通过设置某些参数,然后就可以正常显示中文了。
这次还是直接把这个它的设置方法贴出来吧,让自己不用再找了。
1 | webView.getSettings().setDefaultTextEncodingName("UTF -8");//设置默认为utf-8 |
String.replace()
无法替换成功其实这个问题挺奇怪的,但是也算不上一个问题吧。
这个方法并不会改变调用这个方法的String,而是返回一个替换了之后的String
写着写着忘记了这个,结果浪费了好久的时间。
RecyclerView
如何创建ContextMenu先上成功创建并获取到了所需信息的链接吧!
网上的说话基本上是ListView的,但是RecyclerView与它又不相同。因此按照网上的说法,基本上通过getMenuInfo()
获取到的是空,好伤。如果不是空的话,那么会得到AdapterView.AdapterContextMenuInfo
,这个里面包含了一些信息如position,应该是该项在整个RecyclerView中的位置吧。
网上的做法有两种,一种是:
setOnCreateContextMenuListener()
,但是这样还是无法直接将所需要的信息传递进来,所以还需要设置setOnMenuItemClickListener()
,用来处理点击该项后需要进行的事项,因此,这这里可以直接获取当前RecyclerView中的item并对其进行相关的操作。这个做法来自链接。1 | itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> { |
可以参考这段代码,没有尝试过,但是mark一下吧!链接,这种做法挺靠谱的感觉。
关键是下面这段代码,其余的可以按照ListView的那样进行操作。
1 | public class RecyclerViewImplementsContextMenu extends RecyclerView { |
Intent
中如何传递一个普通对象在做小应用的时候遇到了这种问题,网上的解答也比较完整。
方式一:Serializable 方式
使用Intent 来传递对象通常有两种实现方式,Serializable 和Parcelable,我们先来学习一下第一种的实现方式。
Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。至于序列化的方法也很简单,只需要让一个类去实现Serializable 这个接口就可以了。
比如说有一个Person 类,其中包含了name 和age 这两个字段,想要将它序列化就可以这样写:
1 | public class Person implements Serializable{ |
其中get、set 方法都是用于赋值和读取字段数据的,最重要的部分是在第一行。这里让Person 类去实现了Serializable 接口,这样所有的Person 对象就都是可序列化的了。
接下来在FirstActivity 中的写法非常简单:
1 | Person person = new Person(); |
可以看到,这里我们创建了一个Person 的实例,然后就直接将它传入到putExtra()方法中了。由于Person 类实现了Serializable 接口,所以才可以这样写。
接下来在SecondActivity 中获取这个对象也很简单,写法如下:
1 | Person person = (Person) getIntent().getSerializableExtra("person_data"); |
这里调用了getSerializableExtra()方法来获取通过参数传递过来的序列化对象,接着再将它向下转型成Person 对象,这样我们就成功实现了使用Intent 来传递对象的功能了。
方式二:Parcelable
除了Serializable 之外,使用Parcelable 也可以实现相同的效果,不过不同于将对象进行序列化,Parcelable 方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent 所支持的数据类型,这样也就实现传递对象的功能了。
下面我们来看一下Parcelable 的实现方式,修改Person 中的代码,如下所示:
1 | public class Person implements Parcelable { |
Parcelable 的实现方式要稍微复杂一些。可以看到,首先我们让Person 类去实现了Parcelable 接口,这样就必须重写describeContents()和writeToParcel()这两个方法。其中describeContents()方法直接返回0 就可以了,而writeToParcel()方法中我们需要调用Parcel的writeXxx()方法将Person 类中的字段一一写出。注意字符串型数据就调用writeString()方法,整型数据就调用writeInt()方法,以此类推。
除此之外,我们还必须在Person 类中提供一个名为CREATOR 的常量,这里创建了Parcelable.Creator 接口的一个实现,并将泛型指定为Person。接着需要重写createFromParcel()和newArray()这两个方法,在createFromParcel()方法中我们要去读取刚才写出的name 和age字段,并创建一个Person 对象进行返回,其中name 和age 都是调用Parcel 的readXxx()方法读取到的,注意这里读取的顺序一定要和刚才写出的顺序完全相同。而newArray()方法中的实现就简单多了,只需要new 出一个Person 数组,并使用方法中传入的size 作为数组大小就可以了。
接下来在FirstActivity 中我们仍然可以使用相同的代码来传递Person 对象,只不过在SecondActivity 中获取对象的时候需要稍加改动,如下所示:
1 | Person person = (Person) getIntent().getParcelableExtra("person_data"); |
注意这里不再是调用getSerializableExtra()方法,而是调用getParcelableExtra()方法来获取传递过来的对象了,其他的地方都完全相同。这样我们就把使用Intent 来传递对象的两种实现方式都学习完了,对比一下,Serializable的方式较为简单,但由于会把整个对象进行序列化,因此效率方面会比Parcelable 方式低一些,所以在通常情况下还是更加推荐使用Parcelable 的方式来实现Intent 传递对象的功能。
作为一名Android开发人员,时常遇到Android Studio抽风的情况。之前也遇到过,没有记录,之后就忘了,还得去重新去查解决办法,真的是有点痛心疾首。所以在这里特地记录下,在开发过程中,所遇到的一些关于AS的一些问题,让自己进步得更快。
修改了原本的包名.
之后R文件也出现了问题, 这个现场截图已经找不到了, 大致是这样的. 所有代码中应用了R文件的地方都出现了错误,并且将鼠标移到其上,可以通过Alt + Enter
导入R文件.
但是这个R文件是上一个包名下的R文件, 导入了也没用, 还是该报错的地方报错. 后来, 找到了Manifest.xml
文件中的package
属性, 发现它是修改包名之前的包名, 所以改了之后, rebuild了一下, 就解决了
如上图所示. 所有的代码基本上修改好了, 开开心心的点了一下Run,结果给了我一大段红色的error…面对这个确实也比较无奈.我感觉这个应该与应用配置有关系, 也就是与那一堆Gradle Scripts
有关系, 但是不知道该修改哪里的哪个参数.不过网上还是有比我先遇到这个问题的人, 解决方案也有了~如下:
I had the same error after renaming/refactoring. What I did was add the applicationId property attribute to my build.gradle file, and set its value to the application package. Like this:
1 | android{ |
from Stack Overflow
直接上方法吧。引用自:Stackoverflow
The details on what is required to use Jack and how can be found in the documentation.
Here is the relevant part from the docs that goes in build.gradle on how to use jackOptions and set the compileOptions for java 1.8.
android {
…
defaultConfig {
…
jackOptions {
enabled true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
UPDATE
The Jack toolchain is now considered deprecated according to this post and work is being done to natively support Java 8 features as part of the Android build system in the coming weeks according to the post.
The post also mentions that there should be little to no work migrating from Jack to the new method in case you still wanted to try enabling Java 8 features with Jack.
UPDATE 2 Preview Built-in Support
You can now try out the new built-in support for Java 8 using the latest Android Studio preview 2.4 preview 6.
For more information on how to enable it or migrate from Jack or Retrolambda see the documentation.
导入TO-DO-MVP
这个Google官方给的例子时,需要把Android Studio的Gradle插件版本从3.0.0-alpha4的版本降为 2.3.3。操作时,碰到了一个问题如下:
1 | Error:(28, 0) Could not find method implementation() for arguments [com.android.support:appcompat-v7:25.3.1] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. |
其实这两个版本间Gradle的一些关键词有一些不同,改回2.3.3之后,需要将关键词也改回来。有点想吐槽~这都不兼容了!
基本上是把Iementation
改回Compile
就好了,注意一些地方的大小写。
正在开发的程序已经被运行起来了,可是这里却显示没有debuggable process。
修改方法真的是一语道破天机啊~
You also should have Tools->Android->Enable ADB Integration active.
出现这种错误有点莫名其妙,网上上的解释是values下面的文件有出错的情况,检查了每个文件,都没出现<string name=""></string>
这种类型的情况。很是苦恼,网上的说法也基本上与此种情况类似。
在检查到gradle.properties
这个配置文件的时候,发现了git无法自动合并而让我们手动解决合并冲突的痕迹,而此冲突却并没有被手动解决。如下图所示:
删掉了不必要的东西之后,一切正常。
出现这种错误,有点不应该。但是同时也说明了,网上的东西只能当参考啊!
记录自己在使用git中所用到的命令,算是半个笔记吧~
--system
选项--global
选项git config --global user.name "John Doe"
git config --global user.email [email protected]
git config --global core.editor vim
git config --list
git config user.name
.gitignore
文件忽略不想进行版本控制的文件。
参考https://github.com/github/gitignore
git add
三个作用:
git status -s
如果嫌弃不带-s
的命令输出的信息太繁杂,那么可以使用这个。
新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。
出现在右边的 M 表示该文件被修改了但是还没放入暂存区,出现在靠左边的 M 表示该文件被修改了并放入了暂存区。
git diff
查看尚未暂存的文件更新了哪些部分git diff --staged
查看已暂存的将要添加到下次提交里的内容
git commit
-m 添加一段信息,作为提交说明
-a 跳过暂存区,直接将已追踪的文件暂存起来并提交
–amend 此次提交的结果替代上次提交的结果
git rm
从已跟踪文件清单中移除(确切地说,是从暂存区域移除),并连带从工作目录中删除指定的文件
-f 删除之前修改过并且已经放到暂存区域的文件
–cached 把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中
git mv
等价于
1 | mv |
git log
-p 显示每次提交的差异
-p -2 显示最近两次的差异
–stat 每次提交的简略的统计信息
–graph 显示 ASCII 图形表示的分支合并历史。
–pretty使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和format(后跟指定格式)。
git reset HEAD <file>...
将文件从暂存区移除
git checkout -- <file>...
将此文件做的文件全部撤销
git init
在执行命令的目录下创建git仓库
git add *
添加所有的文件到缓存区
git commit * -m
提交所有追踪的文件到git仓库
git pull origin master
从远程仓库拉代码到本地git仓库
git push origin master
将自己的代码推送到远程git仓库
git branch
显示所有的分支
git branch -a
显示所有的分支包括远程的分支
git checkout -b branch_name
创建branch_name分支并切换到该分支上
git checkout branch_name
切换到branch_name分支上
这个文件顾名思义是起到忽略作用的,在git仓库中使用此文件,将不需要添加进git仓库的文件排除在外。可是在使用的时候,会遇到向其中添加了文件名,却
不起作用的情况。很奇怪,参考网上的说法,当已经添加该文件进入git仓库后,再在.gitignore中除去该文件,就会遇到这种情况,我就是属于这种情况,这时需要将其从仓库中删除,然后再执行git add
时就会忽略掉该文件..gitignore只对未追踪的文件有过滤效果。可参考如下代码
1 | git rm -r --cached . |
当从远程仓库上面拉下代码之后,其中有若干分支,如若想在本地建立一个分支,并使之与远程分支中的某个分支对应,那么该如何操作呢?
git checkout --track origin/branch_name local_branch_name
这个命令会自动创建local_branch_name
,如果它已经存在了,那么将执行失败~
试了试将所有的feature分支都推送到远程仓库,后来发现那个分支基本上没啥用,在将feature分支merge到dev分支上后,feature分支就一直处于当初的那个状态,当dev一直向前走的时候,你再次回到该feature分支,相当于回到了dev分支之前的某个节点,因此我认为将其推送到远程仓库是没有多大的意义的,所以动起了删掉所有本地和远程仓库中已merge的feature分支。
首先是查看远程仓库里面所含有的feature分支:
1 | asahi@asahis-MBP ~/AndroidStudioProjects/NHKNews master git branch -a |
当使用git branch -d feature-main-page
之后,得到的结果如上,可是我只是删除了本地的分支,远程的分支依然还在,该如何删除这个远程仓库里面的分支呢?有git命令为git push origin --delete origin/feature-main-page
,可是出现错误,不能删除,因此试了另外一个命令git push origin :feature-main-page
,成功删除。然后对于feature-remote分支,直接使用前条命令,可将本地与远程仓库里面的分支一起删除.
再次使用git remote show origin
,查询得到的结果如下:
1 | * remote origin |
总结:超强的总结
这是一个玩具脚本,能在windows和linux上面跑。当时有一个网站提供免费的ss账号,但是账号、密码会定时变更,所以写了这个脚本来爬取免费vpn账号,然后配置好参数,最后双击启动shadowsocks。
好傻吊的玩具,被我校招时一直写简历上面,哈哈。放在 repo 里面,感觉不值得,以文章的形式留个纪念吧!
项目树状结构图:
1 | . |
入口很简单,双击 sss.bat 脚本,代理就自己挂上了。但是貌似在jar包里面也启动了ss代理,搞不懂啊。
1 | java -jar crossGFW.jar |
现在的疑问为什么当时不用Python写,非得用Java。
此处的入口是一个Main方法,它主要抓取免费账号、填充vpn配置和启动ss。
1 | /** |
主要逻辑:
1 | import java.io.BufferedReader; |
没搞明白当时的想法,我为啥还定义了一个 Server POJO类,代码里面并没见到调用呀。
1 | /** |
最魔幻的事情还是发生了,与sss.bat里面的代码貌似有点冲突。
1 | import java.io.IOException; |
也许是后面加的Java代码,但是 who cares,反正它也没有什么实际价值与维护的意义,当做纪念吧~
无U盘安装Linux openSUSE(通过硬盘安装Linux)