Android Studio撤销与SVN或者Git的关联

为何会记录这一个问题,主要是在做项目的过程中出现了一个奇怪的现象,就是直接在文件目录下使用svn上传文件的话,可以看到该目录是与SVN相关联的,可是到了用Android Studio上传代码的时候却发现Android Studio是与Git相关联的。

最终发现可以使用以下方法解决:

在Android Studio上使用Project模式查看代码,在.idea文件夹,在该文件夹下找到vcs.xml。

打开发现如下:

我当时在<mapping directory=”” vcs=”svn” />下面还有很多代码,有一个句是 vcs=”Git”,问题就是出在这里,我把下面的都删了,只保留上面图片的代码就OK了,当然,如果想让Android Studio与SVN取消关联,那么只要将vcs = “svn”改为vcs=“”就OK了。

 

SVN拉取后撤销,恢复未拉取之前的状态

在做项目的时候,一不小心将服务器上的代码覆盖了本地的代码,本来可以使用log查看svn上的历史列表,然后选中某个选项,右键,点击revert to this vision来使代码恢复到任意一个版本。

可是关键是本地的代码还没有上传到svn上,也就是说我们要恢复的代码svn上还没有,那么怎么办呢?

1、右键选中你的项目,按照下图所示选中本地历史:

2、打开历史界面后便可以看到你本地的修改历史记录:

3、选中你想恢复到的某个记录,右键:

点击Revert就可以了

svn统计代码行数(增量)

android代码,两个版本之间,代码行数增加了多少,怎么得出呢?

1.安装TortoiseSVN,在安装时需要安装svn命令行工具。

2、下载StatSVN包,官网:http://www.statsvn.org/index.html 

其实StatSVN就是一个jar包,它的运行需要java运行环境,所以还需要安装java环境

 

完成上面两步之后,接下来的具体工作为:

1、运行cmd,切换到StatSVN的解压目录(假设为D:\statsvn-0.7.0),jar包所在的目录,然后运行命令:

svn co https://……将svn仓库上的代码拉下来。

假如此时代码文件为Code,所在目录为D:\statsvn-0.7.0\Code

 

2、拉取log文件:

svn log -v –xml -r {2019-01-11}:{2019-04-11} > D:\statsvn-0.7.0\Code > D:\statsvn-0.7.0\Code\svn.log

这一句的意思是在D:\statsvn-0.7.0\Code中生成日志文件svn.log,这个日志文件的时间段为2019-01-11至2019-04-10,需要注意的是,拉下来的日志文件是不包括11号的,如果需要拉取所      有时间段的日志,那么应该用下面这一句:

svn log -v –xml > D:\statsvn-0.7.0\Code > D:\statsvn-0.7.0\Code\svn.log

要注意,要指定在拉下来的代码目录里面生成,否则会失败

 

3、既然已经拉取下来的,那么我们就可以对日志文件进行分析,然后从分析的结果里就能得到我们想要的。

运行jar文件。

java -jar statsvn.jar D:\statsvn-0.7.0\Code\svn.log D:\statsvn-0.7.0\Code -charset gbk -output-dir D:\MyLog

D:\MyLog为解析后的文件的所在的目录。

点击解析后的一堆文件中的index.html,浏览器打开,然后便可以看到需要的信息。

Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{…

在做多渠道打包的时候出现了这个错误,在高版本的gradle出现。

 

具体错误为:Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
我的代码为下:

这个在低版本的gradle是行得通的,但是高版本就不行。

高版本的应该这样:

variant.outputs.each改为variant.outputs.all

output.outputFile = new File(outputFile.parent, fileName)改为outputFileName = fileName

解决Error:All flavors must now belong to a named flavor dimension. Learn more at…

低版本的gradle里面不会出现这个错误,高版本出现,不多说,看如何解决

在defaultConfig{}中添加:

flavorDimensions “default”

保证所有的flavor 都属于同一个维度

 

android多渠道打包

链接:http://77blogs.com/?p=55

因为要统计各个市场的下载量和其他数据,所以在打包的时候就需要针对每个渠道单独打包,于是,多渠道打包自然就出现了。

不然一个一个打可真是要命。

1、在AndroidManifest.xml文件的</application>标签里面设置:

2、app的build.gradle里面设置(android {}里面):

(1)、defaultConfig {}里面加上:flavorDimensions “default”

(2)、productFlavors里面写上渠道名与渠道号

(3)、设置输出的apk名称(方便查看):

这个是apk的名称:

def fileName

= “novel_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk”

 

defaultConfig.versionName:版本号。

releaseTime():时间(具体方法接下来说)

variant.productFlavors[0].name:渠道名(这里为v1或者v2)

apk名称为novel_v  +  版本号   +   时间   +   渠道名

 

(4)、releaseTime()方法(写在build.gradle的最外层)

3、验证:

(1)、代码中获取渠道号

(2)、打debug包

然后运行,便可以打v1渠道的包,在看代码中打印出来的渠道是否正确

 

若是所有的渠道都是相同的渠道号,可以这样:

哪里有不对的地方欢迎指出。

 

若是有疑问,或许这两篇能够帮到你:

https://www.cnblogs.com/tangZH/p/10764638.html

https://www.cnblogs.com/tangZH/p/10764568.html

Gradle for Android ( 构建变体 )

链接http://77blogs.com/?p=38

有时候我们一个app需要有不同的版本,不同的版本又会使用不同的配置,我们可以使用gradle进行管理。


  • Build types
  • Product flavors
  • Build variants
  • Signing configurations

 


 

一、构建版本Build types:

常见的构建版本有debug与release。

自定义构建版本:

除了debug构建版本不需要签名外,其它的都是需要配置签名的,不然无法运行在手机上,该版本定义了新的applicationId与版本号。不同构建版本的applicationId如下:

  • Debug: com.package
  • Release: com.package
  • Staging: com.package.staging

 

也可以采用继承的方式:

custom继承debug构建版本的配置,custom中的配置会覆盖debug的配置。

 

在BuildConfig中添加变量

之后我们可以看到:

注意如果要添加的是String,那么双一号里面需要再一个双引号标识字符串“\”custom app\””,斜杆是对里面双引号进行转义。

Source sets

当创建了一个新的build type之后,Gradle也会创建一个新的source set。默认的source set目录会放在相同的Build Type的目录下。当你创建一个新的build type时,该目录不会自动创建,你必须在你使用代码与资源前自己为每一个build type创建source set目录。
三种buildType的目录结构如下:

假如我们自己建立custom的source set

我们使用不同的构建版本便会使用不同的source set。当使用不同的source sets的时候,资源文件的处理需要特殊的方式。Drawables和layout文件将会复写在main中的重名文件,但是values文件下的资源不会。gradle将会把这些资源连同main里面的资源一起合并。(如果出现资源重复异常,请clean一下工程)

例如,在main中的string.xml为:

在custom版本中为:

当我们构建custom版本的时会合并为:

当你创建一个新的构建版本而不是custom,最终的strings.xml将会是main目录下的strings.xml。

manifest也和value文件下的文件一样。如果你为你的构建版本创建了一个manifest文件,那么你不必要去拷贝在main文件下的manifest文件,你需要做的是添加标签。Android插件将会为你合并它们。

 

但是需要注意,当我们添加.java文件到custom版本中,你可以添加相同的类到debug和release版本,但是不能添加到main版本。如果你添加了,会抛出异常。这时候我们如果构建custom版本,那么便会使用custom对应source set中的.java文件。

 


 

依赖包

每一个构建版本都有自己的依赖包,gradle自动为每一个构建的版本创建不同的依赖配置。如果你想为debug版本添加一个logging框架,你可以这么做:

 


product flavors

不同的生产版本。

product flavors极大简化了基于相同的代码构建不同版本的app。

创建product flavors

这时候AS 3.0以上会报错ERROR: All flavors must now belong to a named flavor dimension

没有给它们设置一个风味维度,我们可以加上

flavorDimensions “default”

给这些产品版本默认一个风味维度,具体有何作用,等会会讲。

 

这时候我们会在左下角的窗口看到这么多个变体:

 

如果找不到该窗口,可以在这里打开:

 由于我们之前在custom构建版本上设置了applicationIdSuffix “.custom”,所以,当我们运行oppoCustom版本的时候,applicationId为oppo.custom

 

Source Set

product Flavors也有自己的代码文件夹。创建一个特殊的版本就像创建一个文件夹那么简单。如下图所示:

但是值得注意的是,我们无法再vivo文件夹里相同的包中添加构建版本已经有的.java文件,添加了会报异常。而对于资源文件,我们可以添加构建版本里面有的文件,但是这个产品版本所对应的目录的优先级低于Build type,也就是说,当Custom目录有一张图片,vivo目录也有一张图片,那么当我们运行打包vivoCustom版本的时候,使用的是custom里面的图片。除非我们建立的文件夹是vivoCustom,那么它的优先级便会是最高的。

 

Multiflavor variants

在某些情况下,你可能希望创建一些联合的Product Flavors,这个时候便要使用到我们刚刚所说的flavorDimensions 了。

设想一下,假如我们需要打包两个渠道的app:vivo和oppo,而这两个渠道的app各自有付费版与免费版,那么我们就需要用到多维度了。

 

首先定义两个维度:渠道channel,付费与免费:money

flavorDimensions “channel”,”money”

当你添加了flavor dimensions,你就需要为每个flavor添加dimension,否则会提示错误。

之后我们可以看到这么多个变体:

而我们定义多个维度的顺序是很重要的,因为当你在各个维度各自定义了同一个常量的值,比如:buildConfigField(“String”, “name”,”\”custom app\””),总是以第一维度的为准。

 


 

Build variants

构建变体

构建变体是构建版本和生产版本的结合体。当你创建了一个构建版本或者生产版本,同样的,新的变体也会被创建。

像我们上图便有这么多的变体:

我们可以在这个窗口进行切换,然后运行不同的变体。

tasks

Android Plugin会为每一个配置的Build Variant创建Tasks。一个新的Android App拥有Debug和Release两种Build Types,所以默认的就会有两个Task,一个是assembleDebug一个是assembleRelease来构建不同的APK。当添加一个新的Build Type的时候,一个新的Task也就会被创建,一旦你开始添加Flavors,一整套Tasks就会被创建,因为每一个BuildType的Tasks都会为每个Product Flavor联合。

Source sets

构建变体也可以有自己的资源文件夹,举个例子,你可以有src/vivoVipCustom/java/。原理与上面的类似


 

Resource and mainfest merging

Android Plugin需要在打包前对Main的SourceSet以及BuildType的SourceSet进行一次Merge。而且Library工程也会提供额外的资源,它们也会被Merge,例如Manifest.xml等等。也会在其中声明一些权限等。

Resource和Manifest.xml的优先级顺序如下:

如果一个资源在main中和在flavor中定义了,那么那个在flavor中的资源有更高的优先级。这样那个在flavor文件夹中的资源将会被打包到apk。而在依赖项目申明的资源总是拥有最低优先级。

 

当然,如果你建立的目录是变体的目录入:vivoVipCustom,那么它的优先级自然是高于Build type


 

创建构建变体

关于如何构建变量,上面已经说了,不再重复。

resValue “color”, “colorfree”, “#ff8888″表示添加颜色名为colorfree的颜色


变体过滤器

忽略某个变体也是可行的。这样你可以加速你的构建当使用assemble的时候,这样你列出的tasks将不会执行那么你不需要的变体。你可以使用过滤器,在build.gradle中添加代码如下所示:

发现相关的变体不见了:

 


Signing Configurations

在你发布你的应用之前,你需要为你的app私钥签名。如果你有付费版和免费版,你需要有不同的key去签名不同的变体。这就是配置签名的好处。配置签名可以这样定义:

在这个例子中,我们创建了2个不同的签名配置。debug配置是as默认的,其使用了公共的keystore和password,所以没有必要为debug版本创建签名配置了。custom配置使用了initWith()方法,其会复制其他的签名配置。这意味着custom和debug的key是一样的。

release配置使用了storeFile,定义了key alias和密码。当然这不是一个好的选择,你需要在 Gradle properties文件中配置。

 

当你定义了签名配置后,你需要应用它们。构建版本都有一个属性叫做signingConfig,你可以这么干:

上例使用了buildTypes,但是你可能需要对每个版本生成不同的验证,你可以这么定义:

当签名一个Flavor版本的时候,你需要重写BuildType中的签名配置。当需要使用相同的BuildType不同版本的Flavors的签名时,可以通过下述方式:

上面这个例子展示了如何在vivo和oppo的Release版本使用不同的签名,但是却不影响Debug和Custom的BuildType。

Android中Parcelable的使用

转载请标明出处 :http://77blogs.com/?p=286

Parcelable与Serializable

Serializable是Java为我们提供的一个标准化的序列化接口。

Parcelable是Android为我们提供的序列化的接口。

 


 

对比:

1、Parcelable相对于Serializable的使用相对复杂一些。

2、Parcelable的效率相对Serializable也高很多。

3、Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。存储到设备或者网络传输上选择Serializable。

 


 

序列化与反序列化

序列化:将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 。

反序列化:从二进制流(序列)转化为对象的过程。

 

简单使用:

进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。简单看一下:

1、定义Book类,实现Parcelable接口。

 

writeToParcel:序列化过程

Creator与protected Book(Parcel in)配合实现反序列化,转换为对象。

 

注意:类中有多个String或者其它相同对象的话,那么writeToParcel中writeString的顺序是怎么样的,protected Book(Parcel in) {}中readString的顺序就得是怎么样的。

 

2、mainActivity中:

 

3、另一个Activity获取:

 

输出:

 


 

Book类里面有其它对象:

如果Book类里面有其他对象(比如实体类Data)的话,那么Data也需要实现Parcelable接口,用法与上面的Book类一样。

writeToParcel里面需要写上:dest.writeParcelable(data, 0);

protected Book(Parcel in) {}里面需要写上data = in.readParcelable(Data.class.getClassLoader());

 


参考:https://www.jianshu.com/p/df35baa91541