From 0055b78e809307dc612c721002c2e08d8bb05a9a Mon Sep 17 00:00:00 2001 From: Lollypo Date: Mon, 30 Mar 2015 10:43:50 +0800 Subject: [PATCH 01/14] init --- .../readme.md" | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 "others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" diff --git "a/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" "b/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" new file mode 100644 index 00000000..0e853a7e --- /dev/null +++ "b/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" @@ -0,0 +1,123 @@ +Kotlin for Android (II)创建一个工程 +--- + +> +* 原文标题 : Kotlin for Android (II): Create a new project +* 原文链接 : [Kotlin for Android (II): Create a new project](http://antonioleiva.com/kotlin-android-create-project/) +* 译者 : [Lollypo](https://github.com/Lollypo) +* 校对者: +* 状态 : 未完成 + + +After getting a light idea of [what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/), it´s time to configure Android Studio to help us develop Android apps using Kotlin. It requires some steps that only need to be done first time, but some other Gradle configurations will need to be done on every new project. + +For this set of articles, I´ll be creating a reduced version of [Bandhook](https://play.google.com/store/apps/details?id=com.limecreativelabs.bandhook), an app I created some time ago, which will basically connect to a music rest API and return some info about a set of bands. Go to [Bandhook Kotlin on Github](https://github.com/antoniolg/Bandhook-Kotlin) and take a look at the code. + + +###Create a new project and download Kotlin plugin### + + +###Add Kotlin plugin dependency to your application build.gradle### + +Just create a basic Android project with an activity using Android Studio, the same way you would do for a regular project. + +Once done, first thing you´ll need is to download Kotling plugin. Go to Android Studio preferences and search plugins. Once there, use search again to find Kotlin plugin. Install and restart the IDE. + +![kotlin-plugin](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-plugin-e1424632570741.png) + + + +###Configure module build.grade### + +First, apply Kotlin plugin: +```gradle +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +``` +Then, add the Kotlin library to your dependencies: +```gradle +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'org.jetbrains.kotlin:kotlin-stdlib:0.11.91' +} +``` +And finally, you need to add the Kotlin folder we´ll be creating on next step to your sources folders: +```gradle +android { + compileSdkVersion 22 + buildToolsVersion "22.0.0" + + ... + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } +} +``` +Alternatively, you can skip this step, and after doing next ones, use this Android Studio action: +![configure-kotlin-project](http://7xi8kj.com1.z0.glb.clouddn.com/configure-kotlin-project.png) +I prefer doing it manually to keep my Gradle files organized, but this second option could be easier. + + + +###Create Kotlin folder### + +It will be easier if you change the project visualization from ‘Android’ to ‘Project’. Go to ‘app->src->main’ and create a folder called ‘kotlin': +![kotlin-folder](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-folder.png) + + +###Convert java activity to a kotlin file### + +Kotlin plugin can convert from java to kotlin classes. We can convert our current activity to a Kotlin class very easily from ‘Code’ menu, by choosing ‘Convert Java File to Kotlin File': +![convert-java-to-kotlin](http://7xi8kj.com1.z0.glb.clouddn.com/convert-java-to-kotlin-e1424633562637.png) +IDE will suggest to move new file to the Kotlin folder. Click on ‘Move File’ (or move it manually if you don´t see the option). +```java +public class MainActivity : ActionBarActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } + + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + val id = item.getItemId() + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true + } + + return super.onOptionsItemSelected(item) + } +} +``` + + + +###Main differences### + +Just taking a look at previous code, we can see some direct differences. There are many more we´ll be discovering in next posts: + +- Use of colon instead of the word ‘extends’ +- Explicit use of ‘override': in Java, we can use an annotation to make our code more clear, but it´s not a condition. Kotlin will force us use it. +- Use of ‘fun’ for functions: Kotlin is and object-oriented functional language, so it will be very similar to other languages such as Scala. Java methods are represented as functions. +- Function parameters use a different nomenclature: Type and name are written the other way round and separated by a colon +- Optional use of semicolons: we don´t need to finish our lines with a semicolon. We can if we want to, but it can save a lot of time and make our code cleaner if we don´t do it. +- Other small details: In introductory article, I already talked about the ‘?’ symbol on. This indicates the parameter can be null. Nullity is handled different from what we are used in Java + + +###Conclusion### + +Though we can think using a new language will be very difficult, Kotlin is being created by the JetBrains team to be the most easy and interoperable language to cover the needs Java lacks. As Android Studio is also based on a JetBrains product, it will be very easy to integrate to this IDE and start working with it. + +Next article will cover some tips and tricks to make our life easier when developing Android apps with Kotlin. \ No newline at end of file From e080543847937daf2c7a6cebbcebd1b5c7a4adb7 Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Tue, 31 Mar 2015 11:30:12 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E7=AF=87=E6=96=87=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 13 ++ .../readme.md" | 183 ------------------ 2 files changed, 13 insertions(+), 183 deletions(-) create mode 100644 "others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" delete mode 100644 "others/RxJava.Observable\345\217\226\344\273\243AsyncTask\345\222\214AsyncTaskLoader-RxJava Android\346\250\241\347\211\210/readme.md" diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" new file mode 100644 index 00000000..3433a734 --- /dev/null +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -0,0 +1,13 @@ +FaceBook推出的Android图片加载库-Fresco +--- + +> +* 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) +* 校对者: +* 状态 : 翻译中 + + + + +## 原文链接 +[Introducing Fresco: A new image library for Android](https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/) \ No newline at end of file diff --git "a/others/RxJava.Observable\345\217\226\344\273\243AsyncTask\345\222\214AsyncTaskLoader-RxJava Android\346\250\241\347\211\210/readme.md" "b/others/RxJava.Observable\345\217\226\344\273\243AsyncTask\345\222\214AsyncTaskLoader-RxJava Android\346\250\241\347\211\210/readme.md" deleted file mode 100644 index 9c68f82f..00000000 --- "a/others/RxJava.Observable\345\217\226\344\273\243AsyncTask\345\222\214AsyncTaskLoader-RxJava Android\346\250\241\347\211\210/readme.md" +++ /dev/null @@ -1,183 +0,0 @@ -用RxJava.Observable取代AsyncTask和AsyncTaskLoader-RxJava Android模版 ---- - -> -* 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) -* 校对者: [chaossss](https://github.com/chaossss) -* 状态 : 校对中 - - -在网上有很多关于RxJava入门指南的帖子,其中一些是基于Android环境的。但是,我想到目前为止,很多人只是喜欢他们所看到的这些,当要解决在他们的Android项目中出现的具体问题时,他们并不知道如何或者是为什么要使用RxJava。在这一系列的文章中,我想要探索在我工作过的一些依赖于RxJava架构的Android项目中的模式。 - -在文章的开始,我想要处理一些Android开发者在使用RxJava的时候,很容易遇到的状况。从这个角度,我将提供更高级和更合适的解决方案。在这一系列的文章中,我希望可以听到其他开发者在使用RxJava的过程中解决类似的问题,或许他们和我发现的一样呢。 - -#问题一:后台任务 -Android开发者首先遇到的挑战就是如何有效的在后台线程中工作,然后在UI线程中更新UI。这经常是因为需要从web service中获取数据。对于已经有相关经验的你可能会说:“这有什么挑战性?你只需要启动一个AsyncTask,然后所有的工作它就都给你做了。”如果你是这样想的,那么你有一个机会去改善这种状况。这是因为你已经习惯了这种复杂的方式并且忘记这本应该是很简洁的,或者是说你没有处理所有应该处理的边界情况。让我们来谈谈这个。 - -##默认的解决方案:AsyncTask -AsyncTask是在Android里面默认的处理工具,开发者可以做里面一些长时间的处理工作,而不会阻塞用户界面。(注意:最近,AsyncTaskLoader用来处理一些更加具体的数据加载任务,我们以后会再谈谈这个) - -表面上,这似乎很简单,你定义一些代码在后台线程中运行,然后定义一些代码运行在UI线程中,在后台任务处理完之后,它在UI线程会处理从后台任务传递过来的执行结果。 - - private class CallWebServiceTask extends AsyncTask { - - protected Result doInBackground(String... someData) { - Result result = webService.doSomething(someData); - return result; - } - - protected void onPostExecute(Result result) { - if (result.isSuccess() { - resultText.setText("It worked!"); - } - } - } - -使用AsyncTask的最大的问题是在细节的处理上,让我们谈谈这个问题。 - -###错误处理 -这种简单用法的第一个问题就是:“如果出现了错误怎么办?”不幸的是,暂时没有非常好的解决方案。所以很多的开发者最终要继承AsyncTask,然后在doInBackground()中包裹一个try/catch,返回一个,然后根据发生的情况,分发到新定义的例如onSuccess()或者是onError()中。(我也曾经见过仅捕获异常的引用,然后在 onPostExcecute()中进行检查的写法) - -这最终是有点帮助的,但是你必须为你的每个项目写上额外的代码,随着时间的推移,这些自定义的代码在开发者之间和项目之间,可能不会保持很好的一致性和可预见性。 - -###Activity和Fragment的生命周期 -另外一个你必须面对的问题是:“当AsyncTask正在运行的时候,如果我退出Activity或者是旋转设备的话会发生什么?”嗯,如果你只是发送一些数据,之后就不再关心发送结果,那可能是没有问题的,但是如果你需要根据Task的返回结果更新UI呢?如果你不做一些事情阻止的话,那么当你试图去调用Activity或者是view的话,你将得到一个空指针异常导致程序崩溃,因为他们现在是不可见或者是null的。 - -同样,在这个问题上AsyncTask没有做很多工作去帮助你。作为一个开发者,你需要确保保持一个Task的引用,并且要么当Activity正在被销毁的时候取消Task,要么当你试图在onPostExecute()里面更新UI的时候,确保Activity是在一个可达状态。当你只想明确的做一些工作,并且让项目容易维护的时候,这将会继续提高维护项目的难度。 - -###旋转时的缓存(或是其他情况) -当你的用户还是待在当前Activity,仅仅是旋转屏幕会发生什么?在这种情况下,取消Task没有任何意义,因为在旋转之后,你最终还是需要重新启动Task。或者是你不想重启Task,因为状况在一些地方以非幕等的方式发生了突变(because it mutates some state somewhere in a non-idempotent way),但是你确实想要得到结果,因为这样你就可以更新UI来反映这种情况。 - -如果你专门的做一个只读的加载操作,你可以使用AsyncTaskLoader去解决这个问题。但是对于标准的Android方式来说,它还是很沉重,因为缺少错误处理,在Activity中没有缓存,还有很多独有的其他怪癖。 - -###组合的多个Web Server调用 -现在,假如说我们已经想办法把上面的问题都解决了,但是我们现在需要做一些连续的网络求求,每一个请求都需要基于前一个请求的结果。或者是,我们想做一些并发的网络请求,然后把结果合并在一起发送到UI线程,但是,再次抱歉,AsyncTask在这里帮不到你。 - -一旦你开始做这样的事情,随着更多的复杂线程模型的增长,之前的问题会导致处理这样的事情非常的痛苦和苍白无力。如果想要这些线程一起运行,要不你就让它们单独运行,然后回调,或者在其他情况下,让它们在一个后台线程中同步运行,最后复制组成不同。(To chain calls together, you either keep them separate and end up in callback hell, or run them synchronously together in one background task end up duplicating work to compose them differently in other situations.) - -如果要并行运行,你必须创建一个自定义的executor然后传递给AsyncTaskTask,因为默认的AsyncTask不支持并行。并且为了协调并行线程,你需要使用像是CountDownLatchs, Threads, Executors 和 Futures去降低更复杂的同步模式。 - -###可测试性 -抛开这些不说,如果你喜欢测试你的代码,AsyncTask并不能给你带来什么帮助。如果我们不做额外的工作,测试AsyncTask非常困难,它很脆弱并且难以维持。这是一篇有关如何成功测试AsyncTask的[帖子](http://www.making-software.com/2012/10/31/testable-android-asynctask/)。 - -##更好的解决方案:RxJava’s Observable - -幸运的是,一旦我们决定使用RxJava依赖库的时候,我们讨论的这些问题就都迎刃而解了。下面我们看看它能为我们做什么。 - -下面我们将会使用Observables写一个请求代码来替代上面的AsyncTask方式。(如果你使用Retrofit,那么你应该很容易使用,其次它还支持Observable 返回值,并且它工作在一个后台的线程池,无需你额外的工作) - - webService.doSomething(someData) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - result -> resultText.setText("It worked!")), - e -> handleError(e) - ); - -###错误处理 -你可能会注意到,没有做额外的工作,我们已经处理了AsyncTask不会处理的成功和错误的情况,并且我们写了很少的代码。你看到的额外的组件是我们想要Observer 在UI主线程中处理的结果。这样可以让我们前进一点点。并且如果你的sebService对象不想在后台线程中运行,你也可以在这里通过使用.subscribeOn(...) 声明。(注意:这些例子是使用Java 8的lambda语法,使用[Retrolambda](https://github.com/orfjackal/retrolambda)就可以在Android项目中进行使用了,但在我看来,这样做的回报是高于风险的,和写这篇文章相比,我们更喜欢在我们的项目中使用。) - -###Activity和Fragment的生命周期 -现在,我们想在这里利用RxAndroid解决上面提到的生命周期的问题,我们不需要指定mainThread() scheduler(顺便说一句,你只需要导入RxAndroid)。就像下面这样 - - AppObservable.bindFragment(this, webService.doSomething(someData)) - .subscribe( - result -> resultText.setText("It worked!")), - e -> handleError(e) - ); - -我通常的做法是在应用的Base Fragment里面创建一个帮助方法来简化这一点,你可以参考我维护的一个[Base RxFragment](https://github.com/rosshambrick/standardlib/blob/master/src/main/java/com/rosshambrick/standardlib/RxFragment.java) 获得一些指导。 - - bind(webService.doSomething(someData)) - .subscribe( - result -> resultText.setText("It worked!")), - e -> handleError(e) - ); - -如果我们的Activity或者是Fragment不再是可达状态,那么AppObservable.bindFragment()可以在调用链中插入一个垫片,来阻止onNext()运行。如果当Task试图运行的时候,Activity、Fragment是不可达状态,subscription 将会取消订阅并且停止运行,所以不会存在空指针的风险,程序也不会崩溃。一个需要注意的是,当我们离开Activity和Fragment时,我们会暂时或者是永久的泄露,这取决于问题中的Observable 的行为。所以在bind()方法中,我也会调用LifeCycleObservable机制,当Fragment销毁的时候自动取消。这样做的好处是一劳永逸。 - -所以,这解决了首要的两个问题,但是下面这一个才是RxJava大发神威的地方。 - -###组合的多个Web Server调用 -在这里我不会详细的说明,因为这是一个[复杂的问题](http://reactivex.io/documentation/observable.html),但是通过使用Observables,你可以用非常简单和易于理解的方式完成复杂的事情。这里是一个链式Web Service调用的例子,这些请求互相依赖,在线程池中运行第二批并行调用,然后在将结果返回给Observer之前,对数据进行合并和排序。为了更好的测量,我甚至在里面放置了一个过滤器。所有的业务逻辑都在下面这短短五行代码里面... - - public Observable> getWeatherForLargeUsCapitals() { - return cityDirectory.getUsCapitals() - .flatMap(cityList -> Observable.from(cityList)) - .filter(city -> city.getPopulation() > 500,000) - .flatMap(city -> weatherService.getCurrentWeather(city)) //each runs in parallel - .toSortedList((cw1,cw2) -> cw1.getCityName().compare(cw2.getCityName())); - } - -###旋转时的缓存(或是其他情况) -既然这是一个加载的数据,那么我们可能需要将数据进行缓存,这样当我们旋转设备的时候,就不会触发再次调用全部web service的事件。一种实现的方式是保留Fragment,并且保存一个对Observable 的缓存的引用,就像下面这样: - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setRetainInstance(true); - weatherObservable = weatherManager.getWeatherForLargeUsCapitals().cache(); - } - - public void onViewCreated(...) { - super.onViewCreated(...) - bind(weatherObservable).subscribe(this); - } - -在旋转之后,订阅者的缓存实例就会立即发出和第一次请求相同的请求,防止真实的Web Service请求发生。 - -如果你想要避免缓存的Fragment(并且有很充足的理由去避免它),我们可以通过使用AsyncSubject实现缓存。无论何时被订阅,AsyncSubject 都会重新发出最后的项目。或者我们可以使用BehaviorSubject获得最后的值和新值改变整个应用程序。 - - WeatherListFragment.java - - public void onViewCreated() { - super.onViewCreated() - bind(weatherManager.getWeatherForLargeUsCapitals()).subscribe(this); - } - - WeatherManager.java - - public Observable> getWeatherForLargeUsCapitals() { - if (weatherSubject == null) { - weatherSubject = AsyncSubject.create(); - - cityDirectory.getUsCapitals() - .flatMap(cityList -> Observable.from(cityList)) - .filter(city -> city.getPopulation() > 500,000) - .flatMap(city -> weatherService.getCurrentWeather(city)) - .toSortedList((cw1,cw2) -> cw1.getCityName().compare(cw2.getCityName())) - .subscribe(weatherSubject); - } - return weatherSubject; - } - -因为“缓存”是由Manager单独管理的,它不会与Fragment/Activity的周期绑定,并且在Activity/Fragment中将持续存在。如果你想强迫刷新基于以类似的方式来保留Fragment缓存实例的生命周期事件,你可以这样做: - - - public void onCreate() { - super.onCreate() - if (savedInstanceState == null) { - weatherManager.invalidate(); //invalidate cache on fresh start - } - } - -这件事情的伟大之处在于,它不像是Loaders,我们可以很灵活的缓则缓存很多Activity和Services中的结果。只需要去掉oncreate()中的invalidate()调用,并让你的Manager对象决定何时发出新的气象数据就可以了。可能是一个Timer,或者是用户定位改变,或者是其他任何时刻,这真的没关系。你现在可以控制什么时候如何去更新缓存和重新加载。并且当你的缓存策略发生改变的时候,Fragment和你的Manager对象之间的接口不需要进行改变。它只不过是一个 List的Observer。 - -###可测试性 -测试是我们想要实现干净、简单的最后一个挑战。(让我们忽略一个事实,在测试期间,我们可能想要模拟出实际的Web服务。这样做很简单,下面通过一个接口注入到那些依赖你可能已经正在做的标准模式中。) - -幸运的是,Observables给我们一个简单的方式来将一个异步方法变成同步,你要做的就是使用toblocking()方法。我们看一个测试例子。 - - List results = getWeatherForLargeUsCapitals().toBlocking().first(); - assertEquals(12, results.size()); - -就像这样,我们没有必要去使用Futures或者是CountDownLatchs让做一些脆弱的操作,比如线程睡眠或者是让我们的测试变得很复杂,我们的测试现在是简单、干净、可维护的。 - -##结论 -更新:我已经创建了一对简单的项目来演示[AsyncTask风格](https://github.com/rosshambrick/AsyncExamples)和[AsyncTaskLoader](https://github.com/rosshambrick/rain-or-shine)风格。 - -RxJava,你值得拥有。我们使用rx.Observable来替换AsyncTask和AsyncTaskLoader可实现更加强大和清晰的代码。使用RxJava Observables很快乐,而且我期待能够呈现更多的Android问题的解决方案。 - - -## 原文链接 -[Replace AsyncTask and AsyncTaskLoader with rx.Observable – RxJava Android Patterns](http://stablekernel.com/blog/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/) \ No newline at end of file From c0c168aacbc149535221bb6d3665c88a7563a8c2 Mon Sep 17 00:00:00 2001 From: Lollypo Date: Wed, 1 Apr 2015 16:07:43 +0800 Subject: [PATCH 03/14] update --- .../readme.md" | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git "a/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" "b/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" index 0e853a7e..2a42621a 100644 --- "a/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" +++ "b/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" @@ -9,39 +9,51 @@ Kotlin for Android (II)创建一个工程 * 状态 : 未完成 -After getting a light idea of [what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/), it´s time to configure Android Studio to help us develop Android apps using Kotlin. It requires some steps that only need to be done first time, but some other Gradle configurations will need to be done on every new project. +当我从[what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/)获得一些启发之后,觉得是时候配置下 Android Studio来帮助我们用Kotlin开发Android应用程序了. 其中有些步骤只需要在第一次使用的时候做一次, 但是其他一些Gradle配置需要为每一个新项目做一遍. -For this set of articles, I´ll be creating a reduced version of [Bandhook](https://play.google.com/store/apps/details?id=com.limecreativelabs.bandhook), an app I created some time ago, which will basically connect to a music rest API and return some info about a set of bands. Go to [Bandhook Kotlin on Github](https://github.com/antoniolg/Bandhook-Kotlin) and take a look at the code. +对于本系列文章, 我将创建一个我早些时候创建的[Bandhook](https://play.google.com/store/apps/details?id=com.limecreativelabs.bandhook)的简化版本, 它基本上就是连接到一个基于RESTful的音乐API然后接收一些乐队的信息. 链接到 [Bandhook Kotlin on Github](https://github.com/antoniolg/Bandhook-Kotlin) 查看源代码. -###Create a new project and download Kotlin plugin### +###创建一个新项目然后下载Kotlin插件### +只需要像我们平时的项目一样用Android Studio创建一个简单的带有一个Activity的Android项目. -###Add Kotlin plugin dependency to your application build.gradle### +一旦完成,我们需要做的第一件事就是去下载Kotlin插件. 去到Android Studio的系统设置中然后查找plugins.到达之后,再次使用搜索找到Kotlin插件,安装并重启IDE。 -Just create a basic Android project with an activity using Android Studio, the same way you would do for a regular project. +![kotlin-plugin](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-plugin-e1424632570741.png) -Once done, first thing you´ll need is to download Kotling plugin. Go to Android Studio preferences and search plugins. Once there, use search again to find Kotlin plugin. Install and restart the IDE. +###添加Kotlin插件的依赖到的应用程序的build.gradle中### -![kotlin-plugin](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-plugin-e1424632570741.png) +该项目的根build.gradle需要添加一个新的依赖,这个依赖将会被Kotlin插件要求以在主Module中使用: +```gradle +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.3' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.11.91' + } +} +``` -###Configure module build.grade### +###配置Module的build.grade### -First, apply Kotlin plugin: +首先, 应用Kotlin插件: ```gradle apply plugin: 'com.android.application' apply plugin: 'kotlin-android' ``` -Then, add the Kotlin library to your dependencies: +接着, 添加Kotlin库到你的依赖: ```gradle dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'org.jetbrains.kotlin:kotlin-stdlib:0.11.91' } ``` -And finally, you need to add the Kotlin folder we´ll be creating on next step to your sources folders: +最后, 你需要添加我们在下一个步骤创建的Kotlin文件夹: ```gradle android { compileSdkVersion 22 @@ -54,22 +66,28 @@ android { } } ``` -Alternatively, you can skip this step, and after doing next ones, use this Android Studio action: +或者,你可以跳过这一步,当做完下一个时,使用这个Android Studio的操作: + ![configure-kotlin-project](http://7xi8kj.com1.z0.glb.clouddn.com/configure-kotlin-project.png) -I prefer doing it manually to keep my Gradle files organized, but this second option could be easier. + +我更倾向于手动去做以保持我的Gradle文件有整洁有序, 但第二个选项可能更容易。 -###Create Kotlin folder### +###创建Kotlin文件夹### + +如果你将项目的视图从‘Android’转到‘Project’,那将会非常容易。依次选择‘app->src->main’ 然后创建一个名为 ‘kotlin'的文件夹: -It will be easier if you change the project visualization from ‘Android’ to ‘Project’. Go to ‘app->src->main’ and create a folder called ‘kotlin': ![kotlin-folder](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-folder.png) -###Convert java activity to a kotlin file### -Kotlin plugin can convert from java to kotlin classes. We can convert our current activity to a Kotlin class very easily from ‘Code’ menu, by choosing ‘Convert Java File to Kotlin File': +###将Java activity转换成Kotlin文件### + +Kotlin插件能将Java转换为Kotlin类. We can convert our current activity to a Kotlin class very easily from ‘Code’ menu, by choosing ‘Convert Java File to Kotlin File': + ![convert-java-to-kotlin](http://7xi8kj.com1.z0.glb.clouddn.com/convert-java-to-kotlin-e1424633562637.png) + IDE will suggest to move new file to the Kotlin folder. Click on ‘Move File’ (or move it manually if you don´t see the option). ```java public class MainActivity : ActionBarActivity() { @@ -104,20 +122,21 @@ public class MainActivity : ActionBarActivity() { -###Main differences### +###主要区别### + +看一看之前的代码, 我们可以看到一些明显的差异。 其中很大一部分我们将会在下一篇文章讲解到: -Just taking a look at previous code, we can see some direct differences. There are many more we´ll be discovering in next posts: +- 使用冒号,不是'extends'。 +- 显式使用‘override': 在Java中, 我们可以使用一个注释使我们的代码更清晰,但它不是必要条件. Kotlin将迫使我们使用它. +- 函数则使用‘fun’关键字: Kotlin是一个面向对象的函数式语言, 因此可能会与其他语言类似,例如Scala. Java方法表示为函数。 +- 函数参数命名规则不同: 类型和名称都写在相反的位置,并用冒号隔开。 +- 分号可选: 我们不需要在行的结尾处加上分号。如果我们想要也可以加上, 但如果我们不这样做,它就可以节省大量的时间,并使我们的代码整洁。 +- 其他小细节: 在简介一文中, 我已经说到了 ‘?’ 的意义. 这表明参数可以为空。NULL的处理方式不同于Java。 -- Use of colon instead of the word ‘extends’ -- Explicit use of ‘override': in Java, we can use an annotation to make our code more clear, but it´s not a condition. Kotlin will force us use it. -- Use of ‘fun’ for functions: Kotlin is and object-oriented functional language, so it will be very similar to other languages such as Scala. Java methods are represented as functions. -- Function parameters use a different nomenclature: Type and name are written the other way round and separated by a colon -- Optional use of semicolons: we don´t need to finish our lines with a semicolon. We can if we want to, but it can save a lot of time and make our code cleaner if we don´t do it. -- Other small details: In introductory article, I already talked about the ‘?’ symbol on. This indicates the parameter can be null. Nullity is handled different from what we are used in Java -###Conclusion### +###总结### -Though we can think using a new language will be very difficult, Kotlin is being created by the JetBrains team to be the most easy and interoperable language to cover the needs Java lacks. As Android Studio is also based on a JetBrains product, it will be very easy to integrate to this IDE and start working with it. +尽管我们也许会认为使用一门新语言将会非常困难, Kotlin被JetBrains团队开发出来的,要成为最容易和可交互的语言用来覆盖那些Java的不足之处。由于Android Studio也是基于JetBrains的产品,这将让集成到这个IDE中并且开始工作非常简单。 -Next article will cover some tips and tricks to make our life easier when developing Android apps with Kotlin. \ No newline at end of file +下一篇文章将介绍一些让我们在基于Kotlin开发Android应用程序时,能让我们开发过程更简单的奇巧淫技。 \ No newline at end of file From 58c342bab3a11a6662c9413307346e18a5f3c8c1 Mon Sep 17 00:00:00 2001 From: Lollypo Date: Wed, 1 Apr 2015 17:19:16 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=AE=A1=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E9=81=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) rename "others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" => "androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" (76%) diff --git "a/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" similarity index 76% rename from "others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" rename to "androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" index 2a42621a..3f089fb9 100644 --- "a/others/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" +++ "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" @@ -9,7 +9,7 @@ Kotlin for Android (II)创建一个工程 * 状态 : 未完成 -当我从[what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/)获得一些启发之后,觉得是时候配置下 Android Studio来帮助我们用Kotlin开发Android应用程序了. 其中有些步骤只需要在第一次使用的时候做一次, 但是其他一些Gradle配置需要为每一个新项目做一遍. +当我从[what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/)获得一些启发之后,觉得是时候配置下 Android Studio来帮助我们使用Kotlin开发Android应用程序了. 其中有些步骤只需要在初次使用时完成一次, 但是其他一些Gradle配置需要为每一个新项目做一遍. 对于本系列文章, 我将创建一个我早些时候创建的[Bandhook](https://play.google.com/store/apps/details?id=com.limecreativelabs.bandhook)的简化版本, 它基本上就是连接到一个基于RESTful的音乐API然后接收一些乐队的信息. 链接到 [Bandhook Kotlin on Github](https://github.com/antoniolg/Bandhook-Kotlin) 查看源代码. @@ -18,13 +18,13 @@ Kotlin for Android (II)创建一个工程 只需要像我们平时的项目一样用Android Studio创建一个简单的带有一个Activity的Android项目. -一旦完成,我们需要做的第一件事就是去下载Kotlin插件. 去到Android Studio的系统设置中然后查找plugins.到达之后,再次使用搜索找到Kotlin插件,安装并重启IDE。 +一旦完成,我们需要做的第一件事就是去下载Kotlin插件. 去到Android Studio的系统设置中然后查找plugins.之后,再次使用搜索找到Kotlin插件,安装并重启IDE。 ![kotlin-plugin](http://7xi8kj.com1.z0.glb.clouddn.com/kotlin-plugin-e1424632570741.png) ###添加Kotlin插件的依赖到的应用程序的build.gradle中### -该项目的根build.gradle需要添加一个新的依赖,这个依赖将会被Kotlin插件要求以在主Module中使用: +该项目的build.gradle需要添加一个新的依赖,这个依赖将会被Kotlin插件要求以在主Module中使用: ```gradle buildscript { repositories { @@ -66,11 +66,11 @@ android { } } ``` -或者,你可以跳过这一步,当做完下一个时,使用这个Android Studio的操作: +或者,你可以跳过这一步,当做完下一个步骤时,使用这个Android Studio的操作: ![configure-kotlin-project](http://7xi8kj.com1.z0.glb.clouddn.com/configure-kotlin-project.png) -我更倾向于手动去做以保持我的Gradle文件有整洁有序, 但第二个选项可能更容易。 +我更倾向于手动去做以保持我的Gradle文件有整洁有序, 但第二个选项可能较为容易些。 @@ -84,11 +84,11 @@ android { ###将Java activity转换成Kotlin文件### -Kotlin插件能将Java转换为Kotlin类. We can convert our current activity to a Kotlin class very easily from ‘Code’ menu, by choosing ‘Convert Java File to Kotlin File': +Kotlin插件能将Java转换为Kotlin类. 我们可以轻松的通过‘Code’菜单中的‘Convert Java File to Kotlin File'选项转换当前的Activity到Kotlin类 : ![convert-java-to-kotlin](http://7xi8kj.com1.z0.glb.clouddn.com/convert-java-to-kotlin-e1424633562637.png) -IDE will suggest to move new file to the Kotlin folder. Click on ‘Move File’ (or move it manually if you don´t see the option). +IDE将建议你移动新文件到Kotlin文件夹,点击‘Move File’(或者手动完成,假如你没看到这个选项). ```java public class MainActivity : ActionBarActivity() { @@ -126,9 +126,9 @@ public class MainActivity : ActionBarActivity() { 看一看之前的代码, 我们可以看到一些明显的差异。 其中很大一部分我们将会在下一篇文章讲解到: -- 使用冒号,不是'extends'。 +- 使用冒号,而不是'extends'。 - 显式使用‘override': 在Java中, 我们可以使用一个注释使我们的代码更清晰,但它不是必要条件. Kotlin将迫使我们使用它. -- 函数则使用‘fun’关键字: Kotlin是一个面向对象的函数式语言, 因此可能会与其他语言类似,例如Scala. Java方法表示为函数。 +- 函数则使用‘fun’关键字: Kotlin是一个面向对象的函数式语言, 因此可能会与其他语言类似,例如Scala. Java方法被函数的形式表示。 - 函数参数命名规则不同: 类型和名称都写在相反的位置,并用冒号隔开。 - 分号可选: 我们不需要在行的结尾处加上分号。如果我们想要也可以加上, 但如果我们不这样做,它就可以节省大量的时间,并使我们的代码整洁。 - 其他小细节: 在简介一文中, 我已经说到了 ‘?’ 的意义. 这表明参数可以为空。NULL的处理方式不同于Java。 @@ -137,6 +137,6 @@ public class MainActivity : ActionBarActivity() { ###总结### -尽管我们也许会认为使用一门新语言将会非常困难, Kotlin被JetBrains团队开发出来的,要成为最容易和可交互的语言用来覆盖那些Java的不足之处。由于Android Studio也是基于JetBrains的产品,这将让集成到这个IDE中并且开始工作非常简单。 +也许我们会认为使用一门新语言将会非常困难, Kotlin被JetBrains团队开发出来的,要成为最容易和可交互的语言用来覆盖那些Java的不足之处。由于Android Studio也是基于JetBrains的产品,这将让集成到这个IDE中并且开始工作非常简单。 -下一篇文章将介绍一些让我们在基于Kotlin开发Android应用程序时,能让我们开发过程更简单的奇巧淫技。 \ No newline at end of file +下一篇文章将介绍一些让我们在使用Kotlin开发Android应用程序时,能让开发过程更简单的奇巧淫技。 \ No newline at end of file From dd04dc344b6d64cbd658ac2729b9d1677b7e5d4f Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Wed, 1 Apr 2015 19:46:20 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E7=BF=BB=E8=AF=91Fresco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 119 +++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index 3433a734..3607e3f9 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -4,10 +4,127 @@ FaceBook推出的Android图片加载库-Fresco > * 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) * 校对者: -* 状态 : 翻译中 +* 状态 : 等待校对 +快速而又高效的显示图片对Android设备来说是件极其重要的事情,但在过去的几年里,在高效存储图像方面我们面临了很多问题。图片太大,而手机又只有很小的内存,每一个像素都要占用4byte——分别对应R、G、B和alpha通道。如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存。手机的内存通常都很小,特别是Android设备还要将内存分割给各个应用。在一些设备上,Facebook的App仅仅只能分配16M的内存,而一张图片就要占据十分之一! +当你的App内存溢出会发生什么呢?它当然会崩溃!我们开发了一个库来解决这个问题,我们叫它Fresco。它可以管理使用到的图片和内存,从此App不再崩溃。 +##内存领域 +为了理解Facebook到底做了什么工作,我们需要了解在Android可以使用的堆内存之间的区别。Android中每个App的Java堆内存大小都是被严格的限制的。每个对象都是使用Java的new在堆内存实例化,这是内存中相对安全的一块区域。内存有垃圾回收机制,所以当App不在使用内存的时候,系统就会自动把这块内存回收。 + +不幸的是,恰恰是内存回收的进程会导致问题。在进行垃圾回收的时候,Android会完全的停止App,而这比简单的内存分配需要做更多的事情。当你使用App的时候出现卡顿的最常见的原因之一就是这个。如果当人们使用App进行滚动或者是点击按钮的时候出现这种情况,会非常影响用户体验。 + +相比之下,Native堆是由c++的new进行分配的。在Native堆里面有更多可用内存,App只被设备的物理可用内存所限制,而且没有垃圾回收机制或其他东西拖后腿。但是c++程序员必须自己回收所分配的每一块内存,否则就会造成内存泄露,最终导致程序崩溃。 + +Android有另外一种内存区域,叫做Ashmem。它操作起来更像Native堆,但是也有额外的系统调用。Android可以"unpin"内存而不是简单释放。它是一种懒释放,只有当系统真正需要内存的时候才会释放。当Android再次"pins"内存的时候,如果内存没有被释放,那么之前的数据就会被恢复。 +##可消除的Bitmap +Ashmem不能被Java应用直接处理,但是也有一些例外,图片就是其中之一。当你创建一张没有经过压缩的Bitmap的时候,Android的API允许你指定是否是可清除的。 + +``` +BitmapFactory.Options = new BitmapFactory.Options(); +options.inPurgeable = true; +Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); +``` +可清除的Bitmap会驻留在Ashmem中。然后,垃圾回收器不会去自动回收它们。当绘制系统需要对图片进行渲染的时候,Android的系统库就会捡起这些图片内存,用完之后,又把它们扔在那里了。这些没有被使用的内存可以被随时回收,如果一张曾经没有被使用的图片需要再次绘制,系统仅仅需要把它再编码就可以了,这个操作非常的迅速。 + +听起来这好像是一个很好的解决方案,但问题是这个非常迅速的操作是在UI线程上。解码的过程是在GPU上的密集操作,在解码完成之前,UI会一直停滞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个标志位——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非说App里面所有的图片都是相同大小,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但是,我们需要的是一种通用的解决方案,包括Android2.3系统的手机。 + +##自力更生 +我们找到了一种使得UI显示和内存都表现良好的方法。如果我们在非UI主线程里提前把内存保持,并且确保这块内存不会被释放,那么我们就可以在Ashmem里面保持图片的引用,而又不会阻碍UI。幸运的是,Android的NDK有一个函数正好可以完成这个需求,名字叫做AndroidBitmap_lockPixels。这个函数原本是要接着调用unlockPixels来释放内存的。 + +当我们意识到我们没有必要这样做的时候,我们取得了突破。如果我们只调用lockPixels而不调用对应的unlockPixels,那么我们就可以在Java的堆内存里面创建一个安全的图像,并且不会导致UI线程加载缓慢。只需要几行c++代码,我们就完美的解决了这个问题。 + +##用C++的思想写Java代码 +就像《蜘蛛侠》里面说的:“能力越强,责任越强。”使用这种可清除的Bitmap,垃圾回收器不回收它,Ashmem内置的清除机制也不会回收它,这会造成内存泄露,所以我们只能靠自己啦。 + +在c++中,通常的解决方案是建立智能指针类,实现引用计数。这些需要利用到c++的语言特性——复制构造函数、赋值操作符和确定的析构函数。这种语法在Java之中不存在,因为垃圾回收器能够处理这一切。所以我们必须以某种方式在Java中实现C++的这些保证机制。 + +我们创建了两个类去完成这件事。其中一个叫做“SharedReference”,它有addReference和deleteReference两个方法,调用者调用时必须采取基类对象或让它在范围之外。一旦引用计数器归零,资源处理(Bitmap.recycle)就会发生。 + +然而,很显然,让Java开发者去调用这些方法是很容易出错的。Java语言就是为了避免做这样的事情的!所以SharedReference之上,我们构建了CloseableReference类。它不仅实现了Java的Closeable接口,而且也实现了Cloneable接口。它的构造器和clone()方法会调用addReference(),而close()方法会调用deleteReference()。所以Java开发者需要遵守下面两条简单的的规则: + +1. 在分配CloseableReference新对象的时候,调用.clone()。 +2. 在超出作用域范围的时候,调用.close(),这通常是在finally代码块中。 + +这些规则可以有效地防止内存泄漏,并让我们在像Fackbook的Android客户端这种大型的Java程序中享受Native内存管理和通信。 + +##不仅仅是加载程序,它是一个管道 +在移动设备上显示图片需要很多的步骤: +![](http://i2.tietuku.com/4480c88a0d8004bf.png) +几个优秀的开源库都是按照这个顺序执行的,比如 Picasso,Universal Image Loader,Glide和 Volley等等。上面这些开源库为Android的发展做出了非常重要的贡献。我们相信Fresco在几个重要方面会表现的更好。 + +我们的不同之处在于把上面的这些步骤看作是管道,而不仅仅是加载器。每一个步骤和其他方面应该是尽可能独立的,把数据和参数传递进去,然后产生一个输出,就这么简单。它应该可以做一些操作,不管是并行还是串行。一些操作只能在特性条件下才能执行。一些有特殊要求的在线程上执行。除此之外,当我们考虑改进图像的时候,所有的图片就会变得非常复杂。很多人在低网速情况下使用Facebook,我们想要这些人能够尽快的看到图片,甚至经常是在图片没有完全下载完之前。 + +##不要烦恼,拥抱stream +在Java中,异步代码历来都是通过Future机制来执行的。在另外的线程里面代码被提交执行,然后一个类似Future的对象可以检查执行的结果是不是已经完成了。但是,这只在假设只有一种结果的情况下行得通。在处理渐进的图像的时候,我们希望可以完整而且连续的显示结果。 + +我们的解决方式是定义一个更广义的Future版本,叫做DataSource。它提供了一个订阅方法,调用者必须传入一个DataSubscriber和Executor。DataSubscriber可以从DataSource获取到处理中和处理完毕的结果,并且提供了很简单的方法来区分。因为我们需要非常频繁的处理这些对象,所以必须有一个明确的close调用,幸运的是,DataSource本身就是Closeable。 + +在后台,每一个箱子上面都实现了一个叫做“生产者/消费者”的新框架。在这个问题是,我们是从[ReactiveX](http://reactivex.io/)获取的灵感。我们的系统拥有和[RxJava](https://github.com/ReactiveX/RxJava)相似的接口,但是更加适合移动设备,并且有内置的对Closeables的支持。 + +保持简单的接口。Producer只有一个叫做produceResults的方法,这个方法需要一个Consumer对象。反过来,Consumer有一个onNewResult方法。 + +我们使用像这样的系统把Producer联系起来。假设我们有一个producer的工作是把类型I转化为类型O,那么它看起来应该是这个样子: + +``` +public class OutputProducer implements Producer { + + private final Producer mInputProducer; + + public OutputProducer(Producer inputProducer) { + this.mInputProducer = inputProducer; + } + + public void produceResults(Consumer outputConsumer, ProducerContext context) { + Consumer inputConsumer = new InputConsumer(outputConsumer); + mInputProducer.produceResults(inputConsumer, context); + } + + private static class InputConsumer implements Consumer { + private final Consumer mOutputConsumer; + + public InputConsumer(Consumer outputConsumer) { + mOutputConsumer = outputConsumer; + } + + public void onNewResult(I newResult, boolean isLast) { + O output = doActualWork(newResult); + mOutputConsumer.onNewResult(output, isLast); + } + } +} +``` + +这可以使我们把非常复杂的步骤串起来,同时也可以保持他们逻辑的独立性。 + +##动画全覆盖 +使用Facebook的人都非常喜欢Stickers,因为它可以以动画形式存储GIF和Web格式。如果支持这些格式,就需要面临新的挑战。因为每一个动画都是由不止一张图片组成的,你需要解码每一张图片,存储在内存里,然后显示出来。对于大一点的动画,把每一帧图片放在内存是不可行的。 + +我们建立了AnimatedDrawable,一个强大的可以呈现动画的Drawable,同时支持GIF和WebP格式。AnimatedDrawable实现标准的Android Animatable接口,所以调用者可以随意的启动或者停止动画。为了优化内存使用,如果图片足够小的时候,我们就在内存里面缓存这些图片,但是如果太大,我们可以迅速的解码这些图片。这些行为调用者是完全可控的。 + +所有的后台都用c++代码实现。我们保持一份解码数据和元数据解析,如宽度和高度。我们引用技术数据,它允许多个Java端的Drawables同时访问一个WebP图像。 + +##如何去爱你?我来告诉你... +当一张图片从网络上下载下来之后,我们想显示一张占位图。如果瞎子失败了,我们就会显示一个错误标志。当图片加载完之后,我们有一个渐变动画。通过使用硬件加速,我们可以按比例放缩,或者是矩阵变换成我们想要的大小然后渲染。我们不总是按照图片的中心进行放缩,那么我们可以自己定义放缩的聚焦点。有些时候,我们想显示圆角甚至是圆形的图片。所有的这些操作都应该是迅速而平滑的。 + +我们之前的实现是使用Android的View对象——时机到了,可以使用ImageView替换出占位的View。这个操作是非常慢的。改变View会让Android强制刷新整个布局,当用户滑动的时候,这绝对不是你想看到的效果。比较明智的做法是使用Android的Drawables,它可以迅速的被替换。 + +所以我们创建了Drawee。这是一个像MVC架构的图片显示框架。该模型被称为DraweeHierarchy。它被实现为Drawables的一个层,对于底层的图像而言,每一个曾都有特定的功能——成像、层叠、渐变或者是放缩。 + +DraweeControllers通过管道的方式连接到图像上——或者是其他的图片加载库——并且处理后台的图片操作。他们从管道接收事件并决定如何处理他们。他们控制DraweeHierarchy实际上的操作——无论是占位图片,错误条件或是完成的图片。 + +DraweeViews只有有限的功能,但他提供的这些是具有决定性的。他们监听Android的View不再显示在屏幕上的系统事件。当图片离开屏幕的时候,DraweeView可以告诉DraweeController关闭使用的图像资源。这可以避免内存泄露。此外,控制器会告诉图片管道取消网络请求,如果它已经不在屏幕范围内的话。因此,像Fackbook那样滚动一长串的图片的时候,不会频繁的网络请求。 + +通过这些努力,显示图片的辛苦操作一去不复返了。调用代码只需要实例化一个DraweeView,然后指定一个URI和其他可选的参数就可以了。剩下的一切都会自动完成。开发人员不需要担心管理图像内存,或更新图像流。Fresco为他们把一切都做了。 + +##Fresco +完成这个图像显示和操作复杂的工具库之后,我们想要把它分享到Android开发者社区。我们很高兴的宣布,从今天起,这个项目已经作为[开源代码](http://github.com/facebook/fresco)了! + +壁画是绘画技术,几个世纪以来一直受到世界各地人们的欢迎。我们许多伟大的艺术家使用这种名字,从意大利文艺复兴时期的大师拉斐尔到壁画艺术家斯里兰卡。我们并不是假装达到这个伟大的水平,我们真的希望Android开发者能像我们当初享受创建这个开源库的过程一样,非常享受的使用它。 + +##更多 +[Fresco中文文档](http://fresco-cn.org/) ## 原文链接 [Introducing Fresco: A new image library for Android](https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/) \ No newline at end of file From 265bbc027b9492702e33f6d0691cd3e3ec6d162a Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Wed, 1 Apr 2015 21:23:49 +0800 Subject: [PATCH 06/14] modify some bug --- .../readme.md" | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index 3607e3f9..f212e3f2 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -10,12 +10,12 @@ FaceBook推出的Android图片加载库-Fresco 当你的App内存溢出会发生什么呢?它当然会崩溃!我们开发了一个库来解决这个问题,我们叫它Fresco。它可以管理使用到的图片和内存,从此App不再崩溃。 -##内存领域 -为了理解Facebook到底做了什么工作,我们需要了解在Android可以使用的堆内存之间的区别。Android中每个App的Java堆内存大小都是被严格的限制的。每个对象都是使用Java的new在堆内存实例化,这是内存中相对安全的一块区域。内存有垃圾回收机制,所以当App不在使用内存的时候,系统就会自动把这块内存回收。 +##内存区 +为了理解Facebook到底做了什么工作,在此之前我们需要了解在Android可以使用的堆内存之间的区别。Android中每个App的Java堆内存大小都是被严格的限制的。每个对象都是使用Java的new在堆内存实例化,这是内存中相对安全的一块区域。内存有垃圾回收机制,所以当App不在使用内存的时候,系统就会自动把这块内存回收。 -不幸的是,恰恰是内存回收的进程会导致问题。在进行垃圾回收的时候,Android会完全的停止App,而这比简单的内存分配需要做更多的事情。当你使用App的时候出现卡顿的最常见的原因之一就是这个。如果当人们使用App进行滚动或者是点击按钮的时候出现这种情况,会非常影响用户体验。 +不幸的是,恰恰是负责内存回收的进程会导致一些问题。在进行垃圾回收的时候,Android会暂停整个应用,和简单的内存分配相比,垃圾回收需要做更多的事情,所以如果在你使用App的时候出现卡顿的现象,最常见的原因之一就是这个。当人们使用App进行滚动或者是点击按钮的时候卡顿,会非常的影响用户体验。 -相比之下,Native堆是由c++的new进行分配的。在Native堆里面有更多可用内存,App只被设备的物理可用内存所限制,而且没有垃圾回收机制或其他东西拖后腿。但是c++程序员必须自己回收所分配的每一块内存,否则就会造成内存泄露,最终导致程序崩溃。 +相比之下,Native堆是由C++程序的new进行分配的。在Native堆里面有更多可用内存,App只被设备的物理可用内存所限制,而且没有垃圾回收机制或其他东西拖后腿。但是c++程序员必须自己回收所分配的每一块内存,否则就会造成内存泄露,最终导致程序崩溃。 Android有另外一种内存区域,叫做Ashmem。它操作起来更像Native堆,但是也有额外的系统调用。Android可以"unpin"内存而不是简单释放。它是一种懒释放,只有当系统真正需要内存的时候才会释放。当Android再次"pins"内存的时候,如果内存没有被释放,那么之前的数据就会被恢复。 ##可消除的Bitmap @@ -28,7 +28,7 @@ Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); ``` 可清除的Bitmap会驻留在Ashmem中。然后,垃圾回收器不会去自动回收它们。当绘制系统需要对图片进行渲染的时候,Android的系统库就会捡起这些图片内存,用完之后,又把它们扔在那里了。这些没有被使用的内存可以被随时回收,如果一张曾经没有被使用的图片需要再次绘制,系统仅仅需要把它再编码就可以了,这个操作非常的迅速。 -听起来这好像是一个很好的解决方案,但问题是这个非常迅速的操作是在UI线程上。解码的过程是在GPU上的密集操作,在解码完成之前,UI会一直停滞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个标志位——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非说App里面所有的图片都是相同大小,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但是,我们需要的是一种通用的解决方案,包括Android2.3系统的手机。 +这听起来像一个完美的解决方案,但是问题是Bitmap解码的操作是运行在UI线程的。Bitmap解码是非常消耗CPU资源的,当消耗过大时会引起UI阻塞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个标志位——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非说App里面所有的图片都是相同大小,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但是,我们需要的是一种通用的解决方案,包括Android2.3系统的手机。 ##自力更生 我们找到了一种使得UI显示和内存都表现良好的方法。如果我们在非UI主线程里提前把内存保持,并且确保这块内存不会被释放,那么我们就可以在Ashmem里面保持图片的引用,而又不会阻碍UI。幸运的是,Android的NDK有一个函数正好可以完成这个需求,名字叫做AndroidBitmap_lockPixels。这个函数原本是要接着调用unlockPixels来释放内存的。 @@ -38,7 +38,7 @@ Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); ##用C++的思想写Java代码 就像《蜘蛛侠》里面说的:“能力越强,责任越强。”使用这种可清除的Bitmap,垃圾回收器不回收它,Ashmem内置的清除机制也不会回收它,这会造成内存泄露,所以我们只能靠自己啦。 -在c++中,通常的解决方案是建立智能指针类,实现引用计数。这些需要利用到c++的语言特性——复制构造函数、赋值操作符和确定的析构函数。这种语法在Java之中不存在,因为垃圾回收器能够处理这一切。所以我们必须以某种方式在Java中实现C++的这些保证机制。 +在c++中,通常的解决方案是建立智能指针类,实现引用计数。这些需要利用到c++的语言特性——拷贝构造函数、赋值操作符和确定的析构函数。这种语法在Java之中不存在,因为垃圾回收器能够处理这一切。所以我们必须以某种方式在Java中实现C++的这些保证机制。 我们创建了两个类去完成这件事。其中一个叫做“SharedReference”,它有addReference和deleteReference两个方法,调用者调用时必须采取基类对象或让它在范围之外。一旦引用计数器归零,资源处理(Bitmap.recycle)就会发生。 @@ -106,7 +106,7 @@ public class OutputProducer implements Producer { 所有的后台都用c++代码实现。我们保持一份解码数据和元数据解析,如宽度和高度。我们引用技术数据,它允许多个Java端的Drawables同时访问一个WebP图像。 ##如何去爱你?我来告诉你... -当一张图片从网络上下载下来之后,我们想显示一张占位图。如果瞎子失败了,我们就会显示一个错误标志。当图片加载完之后,我们有一个渐变动画。通过使用硬件加速,我们可以按比例放缩,或者是矩阵变换成我们想要的大小然后渲染。我们不总是按照图片的中心进行放缩,那么我们可以自己定义放缩的聚焦点。有些时候,我们想显示圆角甚至是圆形的图片。所有的这些操作都应该是迅速而平滑的。 +当一张图片从网络上下载下来之后,我们想显示一张占位图。如果下载失败了,我们就会显示一个错误标志。当图片加载完之后,我们有一个渐变动画。通过使用硬件加速,我们可以按比例放缩,或者是矩阵变换成我们想要的大小然后渲染。我们不总是按照图片的中心进行放缩,那么我们可以自己定义放缩的聚焦点。有些时候,我们想显示圆角甚至是圆形的图片。所有的这些操作都应该是迅速而平滑的。 我们之前的实现是使用Android的View对象——时机到了,可以使用ImageView替换出占位的View。这个操作是非常慢的。改变View会让Android强制刷新整个布局,当用户滑动的时候,这绝对不是你想看到的效果。比较明智的做法是使用Android的Drawables,它可以迅速的被替换。 From fb340bb5c1392de337c5f3580c71bb1ea42a0f57 Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Wed, 1 Apr 2015 22:21:20 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E6=A0=A1=E5=AF=B9=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index f212e3f2..485a7b9c 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -3,21 +3,24 @@ FaceBook推出的Android图片加载库-Fresco > * 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) -* 校对者: -* 状态 : 等待校对 +* 校对者: [Chaossss](https://github.com/chaossss) +* 校对者: [bboyfeiyu](https://github.com/bboyfeiyu) +* 校对者: [BillionWang](https://github.com/BillionWang) +* 状态 : 校对完成 -快速而又高效的显示图片对Android设备来说是件极其重要的事情,但在过去的几年里,在高效存储图像方面我们面临了很多问题。图片太大,而手机又只有很小的内存,每一个像素都要占用4byte——分别对应R、G、B和alpha通道。如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存。手机的内存通常都很小,特别是Android设备还要将内存分割给各个应用。在一些设备上,Facebook的App仅仅只能分配16M的内存,而一张图片就要占据十分之一! +在Android设备上面,快速高效的显示图片是极为重要的。过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题。图片太大,但是手机的内存却很小。每一个像素的R、G、B和alpha通道总共要占用4byte的空间。如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存。手机的内存通常很小,特别是Android设备还要给各个应用分配内存。在某些设备上,分给Facebook App的内存仅仅有16MB。一张图片就要占据其内存的十分之一。 当你的App内存溢出会发生什么呢?它当然会崩溃!我们开发了一个库来解决这个问题,我们叫它Fresco。它可以管理使用到的图片和内存,从此App不再崩溃。 ##内存区 为了理解Facebook到底做了什么工作,在此之前我们需要了解在Android可以使用的堆内存之间的区别。Android中每个App的Java堆内存大小都是被严格的限制的。每个对象都是使用Java的new在堆内存实例化,这是内存中相对安全的一块区域。内存有垃圾回收机制,所以当App不在使用内存的时候,系统就会自动把这块内存回收。 -不幸的是,恰恰是负责内存回收的进程会导致一些问题。在进行垃圾回收的时候,Android会暂停整个应用,和简单的内存分配相比,垃圾回收需要做更多的事情,所以如果在你使用App的时候出现卡顿的现象,最常见的原因之一就是这个。当人们使用App进行滚动或者是点击按钮的时候卡顿,会非常的影响用户体验。 +不幸的是,内存进行垃圾回收的过程正是问题所在。当内存进行垃圾回收时,内存不仅仅进行了垃圾回收,还把 Android 应用完全终止了。这也是用户在使用 App 时最常见的卡顿或短暂假死的原因之一。这会让正在使用 App 的用户非常郁闷,然后他们可能会焦躁地滑动屏幕或者点击按钮,但 App 唯一的响应就是:在 App 恢复正常之前,请求用户耐心等待 -相比之下,Native堆是由C++程序的new进行分配的。在Native堆里面有更多可用内存,App只被设备的物理可用内存所限制,而且没有垃圾回收机制或其他东西拖后腿。但是c++程序员必须自己回收所分配的每一块内存,否则就会造成内存泄露,最终导致程序崩溃。 +相比之下,Native堆是由C++程序的new进行分配的。在Native堆里面有更多可用内存,App只被设备的物理可用内存限制,而且没有垃圾回收机制或其他东西拖后腿。但是c++程序员必须自己回收所分配的每一块内存,否则就会造成内存泄露,最终导致程序崩溃。 + +Android有另外一种内存区域,叫做Ashmem。它操作起来更像Native堆,但是也有额外的系统调用。Android 在操作 Ashmem 堆时,会把该堆中存有数据的内存区域从 Ashmem 堆中抽取出来,而不是把它释放掉,这是一种弱内存释放模式;被抽取出来的这部分内存只有当系统真正需要更多的内存时(系统内存不够用)才会被释放。当 Android 把被抽取出来的这部分内存放回 Ashmem 堆,只要被抽取的内存空间没有被释放,之前的数据就会恢复到相应的位置。 -Android有另外一种内存区域,叫做Ashmem。它操作起来更像Native堆,但是也有额外的系统调用。Android可以"unpin"内存而不是简单释放。它是一种懒释放,只有当系统真正需要内存的时候才会释放。当Android再次"pins"内存的时候,如果内存没有被释放,那么之前的数据就会被恢复。 ##可消除的Bitmap Ashmem不能被Java应用直接处理,但是也有一些例外,图片就是其中之一。当你创建一张没有经过压缩的Bitmap的时候,Android的API允许你指定是否是可清除的。 @@ -26,9 +29,9 @@ BitmapFactory.Options = new BitmapFactory.Options(); options.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); ``` -可清除的Bitmap会驻留在Ashmem中。然后,垃圾回收器不会去自动回收它们。当绘制系统需要对图片进行渲染的时候,Android的系统库就会捡起这些图片内存,用完之后,又把它们扔在那里了。这些没有被使用的内存可以被随时回收,如果一张曾经没有被使用的图片需要再次绘制,系统仅仅需要把它再编码就可以了,这个操作非常的迅速。 +经过上面的代码处理后,可清除的Bitmap会驻留在 Ashmem 堆中。不管发生什么,垃圾回收器都不会自动回收这些 Bitmap。当 Android 绘制系统在渲染这些图片,Android 的系统库就会把这些 Bitmap 从 Ashmem 堆中抽取出来,而当渲染结束后,这些 Bitmap 又会被放回到原来的位置。如果一个被抽取的图片需要再绘制一次,系统仅仅需要把它再解码一次,这个操作非常迅速。 -这听起来像一个完美的解决方案,但是问题是Bitmap解码的操作是运行在UI线程的。Bitmap解码是非常消耗CPU资源的,当消耗过大时会引起UI阻塞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个标志位——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非说App里面所有的图片都是相同大小,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但是,我们需要的是一种通用的解决方案,包括Android2.3系统的手机。 +这听起来像一个完美的解决方案,但是问题是Bitmap解码的操作是运行在UI线程的。Bitmap解码是非常消耗CPU资源的,当消耗过大时会引起UI阻塞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个特性——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非 App 里的所有图片大小都相同,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但我们需要的是能够运行在 Android 2.3 - 最新版本中的通用解决方案。 ##自力更生 我们找到了一种使得UI显示和内存都表现良好的方法。如果我们在非UI主线程里提前把内存保持,并且确保这块内存不会被释放,那么我们就可以在Ashmem里面保持图片的引用,而又不会阻碍UI。幸运的是,Android的NDK有一个函数正好可以完成这个需求,名字叫做AndroidBitmap_lockPixels。这个函数原本是要接着调用unlockPixels来释放内存的。 From 6bc38bf8e19ddfe07625e17240263fe0b4c553d0 Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Wed, 1 Apr 2015 22:33:08 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E7=AA=81=E7=84=B6=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E8=BF=98=E6=B2=A1=E6=A0=A1=E5=AF=B9=E5=AE=8C=E3=80=82=E3=80=82?= =?UTF-8?q?=E3=80=82=E5=9D=90=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index 485a7b9c..d171c58b 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -34,9 +34,9 @@ Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); 这听起来像一个完美的解决方案,但是问题是Bitmap解码的操作是运行在UI线程的。Bitmap解码是非常消耗CPU资源的,当消耗过大时会引起UI阻塞。因为这个原因,所以Google不推荐使用这个[特性](http://developer.android.com/intl/zh-cn/reference/android/graphics/BitmapFactory.Options.html#inPurgeable)。现在它们推荐使用另外一个特性——inBitmap。但是这个特性直到Android3.0之后才被支持。即使是这样,这个特性也不是非常有用,除非 App 里的所有图片大小都相同,这对Fackbook来说显然是不适用的。一直到4.4版本,这个限制才被移除了。但我们需要的是能够运行在 Android 2.3 - 最新版本中的通用解决方案。 ##自力更生 -我们找到了一种使得UI显示和内存都表现良好的方法。如果我们在非UI主线程里提前把内存保持,并且确保这块内存不会被释放,那么我们就可以在Ashmem里面保持图片的引用,而又不会阻碍UI。幸运的是,Android的NDK有一个函数正好可以完成这个需求,名字叫做AndroidBitmap_lockPixels。这个函数原本是要接着调用unlockPixels来释放内存的。 +对于上面提到的“解码操作致使 UI 假死”的问题,我们找到了一种同时使 UI 显示和内存管理都表现良好的解决方法。如果我们在 UI 线程进行渲染之前把被抽取的内存区域放回到原来的位置,并确保它再也不会被抽取,那我们就可以把这些图片放在 Ashmem 里,同时不会出现 UI 假死的问题。幸运的是,Android 的 NDK 中有一个函数可以完美地实现这个需求,名字叫做 AndroidBitmap_lockPixels。这个函数最初的目的就是:在调用 unlockPixels 再次抽取内存区域后被执行。 -当我们意识到我们没有必要这样做的时候,我们取得了突破。如果我们只调用lockPixels而不调用对应的unlockPixels,那么我们就可以在Java的堆内存里面创建一个安全的图像,并且不会导致UI线程加载缓慢。只需要几行c++代码,我们就完美的解决了这个问题。 +当我们意识到我们没有必要这样做的时候,我们取得了突破。如果我们只调用lockPixels而不调用对应的unlockPixels,那么我们就可以在Java的堆内存里面创建一个内存安全的图像,并且不会导致UI线程加载缓慢。只需要几行c++代码,我们就完美的解决了这个问题。 ##用C++的思想写Java代码 就像《蜘蛛侠》里面说的:“能力越强,责任越强。”使用这种可清除的Bitmap,垃圾回收器不回收它,Ashmem内置的清除机制也不会回收它,这会造成内存泄露,所以我们只能靠自己啦。 From 8d002181bf6fd60ed3c3a6c6eeb56b41d7850cd1 Mon Sep 17 00:00:00 2001 From: Lollypo Date: Thu, 2 Apr 2015 08:25:19 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E6=A0=A1=E5=AF=B9=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" index 3f089fb9..0af11e7b 100644 --- "a/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" +++ "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" @@ -16,7 +16,7 @@ Kotlin for Android (II)创建一个工程 ###创建一个新项目然后下载Kotlin插件### -只需要像我们平时的项目一样用Android Studio创建一个简单的带有一个Activity的Android项目. +就像你平常做的那样,我们只需要用Android Studio创建一个带Activity的基本Android项目。 一旦完成,我们需要做的第一件事就是去下载Kotlin插件. 去到Android Studio的系统设置中然后查找plugins.之后,再次使用搜索找到Kotlin插件,安装并重启IDE。 From b44efefb92e8c6f4027edc4c02aa7900a186cfd3 Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Thu, 2 Apr 2015 09:10:30 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=A0=A1=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index d171c58b..00f377ee 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -39,7 +39,7 @@ Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); 当我们意识到我们没有必要这样做的时候,我们取得了突破。如果我们只调用lockPixels而不调用对应的unlockPixels,那么我们就可以在Java的堆内存里面创建一个内存安全的图像,并且不会导致UI线程加载缓慢。只需要几行c++代码,我们就完美的解决了这个问题。 ##用C++的思想写Java代码 -就像《蜘蛛侠》里面说的:“能力越强,责任越强。”使用这种可清除的Bitmap,垃圾回收器不回收它,Ashmem内置的清除机制也不会回收它,这会造成内存泄露,所以我们只能靠自己啦。 +就像《蜘蛛侠》里面说的:“能力越强,责任越大。”可清除的 Bitmap 既不会被垃圾回收器回收,也不会被 Ashmem 内置的清除机制处理,这使得使用它们可能会造成内存泄露。所以我们只能靠自己啦。 在c++中,通常的解决方案是建立智能指针类,实现引用计数。这些需要利用到c++的语言特性——拷贝构造函数、赋值操作符和确定的析构函数。这种语法在Java之中不存在,因为垃圾回收器能够处理这一切。所以我们必须以某种方式在Java中实现C++的这些保证机制。 @@ -117,7 +117,7 @@ public class OutputProducer implements Producer { DraweeControllers通过管道的方式连接到图像上——或者是其他的图片加载库——并且处理后台的图片操作。他们从管道接收事件并决定如何处理他们。他们控制DraweeHierarchy实际上的操作——无论是占位图片,错误条件或是完成的图片。 -DraweeViews只有有限的功能,但他提供的这些是具有决定性的。他们监听Android的View不再显示在屏幕上的系统事件。当图片离开屏幕的时候,DraweeView可以告诉DraweeController关闭使用的图像资源。这可以避免内存泄露。此外,控制器会告诉图片管道取消网络请求,如果它已经不在屏幕范围内的话。因此,像Fackbook那样滚动一长串的图片的时候,不会频繁的网络请求。 +DraweeViews 的功能不多,但都是至关重要的。他们监听Android的View不再显示在屏幕上的系统事件。当图片离开屏幕的时候,DraweeView可以告诉DraweeController关闭使用的图像资源。这可以避免内存泄露。此外,如果它已经不在屏幕范围内的话,控制器会告诉图片管道取消网络请求。因此,像Fackbook那样滚动一长串的图片的时候,不会频繁的网络请求。 通过这些努力,显示图片的辛苦操作一去不复返了。调用代码只需要实例化一个DraweeView,然后指定一个URI和其他可选的参数就可以了。剩下的一切都会自动完成。开发人员不需要担心管理图像内存,或更新图像流。Fresco为他们把一切都做了。 From fc4e9d23503cc9afd88ef4f8df99ac0a300db322 Mon Sep 17 00:00:00 2001 From: Chaos <437700255@qq.com> Date: Thu, 2 Apr 2015 09:28:10 +0800 Subject: [PATCH 11/14] Update readme.md --- .../readme.md" | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git "a/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" index 0af11e7b..11d64f52 100644 --- "a/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" +++ "b/androidweekly/Kotlin for Android (II)\345\210\233\345\273\272\344\270\200\344\270\252\345\267\245\347\250\213/readme.md" @@ -5,8 +5,8 @@ Kotlin for Android (II)创建一个工程 * 原文标题 : Kotlin for Android (II): Create a new project * 原文链接 : [Kotlin for Android (II): Create a new project](http://antonioleiva.com/kotlin-android-create-project/) * 译者 : [Lollypo](https://github.com/Lollypo) -* 校对者: -* 状态 : 未完成 +* 校对者: [chaossss](https://github.com/chaossss) +* 状态 : 完成 当我从[what Kotlin is and what it can do for us](http://antonioleiva.com/kotlin-for-android-introduction/)获得一些启发之后,觉得是时候配置下 Android Studio来帮助我们使用Kotlin开发Android应用程序了. 其中有些步骤只需要在初次使用时完成一次, 但是其他一些Gradle配置需要为每一个新项目做一遍. @@ -139,4 +139,4 @@ public class MainActivity : ActionBarActivity() { 也许我们会认为使用一门新语言将会非常困难, Kotlin被JetBrains团队开发出来的,要成为最容易和可交互的语言用来覆盖那些Java的不足之处。由于Android Studio也是基于JetBrains的产品,这将让集成到这个IDE中并且开始工作非常简单。 -下一篇文章将介绍一些让我们在使用Kotlin开发Android应用程序时,能让开发过程更简单的奇巧淫技。 \ No newline at end of file +下一篇文章将介绍一些让我们在使用Kotlin开发Android应用程序时,能让开发过程更简单的奇巧淫技。 From dbc50c11a1e752917ca7383d9bf8c621c417c7f8 Mon Sep 17 00:00:00 2001 From: zhaokaiqiang Date: Thu, 2 Apr 2015 09:33:27 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8E=9F=E6=96=87?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加原文链接 --- .../readme.md" | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" index 00f377ee..2a8eba4c 100644 --- "a/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" +++ "b/others/FaceBook\346\216\250\345\207\272\347\232\204Android\345\233\276\347\211\207\345\212\240\350\275\275\345\272\223-Fresco/readme.md" @@ -2,11 +2,12 @@ FaceBook推出的Android图片加载库-Fresco --- > -* 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) +* 原文链接:[Introducing Fresco: A new image library for Android](https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/) +* 译者 : [ZhaoKaiQiang](https://github.com/ZhaoKaiQiang) * 校对者: [Chaossss](https://github.com/chaossss) * 校对者: [bboyfeiyu](https://github.com/bboyfeiyu) * 校对者: [BillionWang](https://github.com/BillionWang) -* 状态 : 校对完成 +* 状态 : 完成 在Android设备上面,快速高效的显示图片是极为重要的。过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题。图片太大,但是手机的内存却很小。每一个像素的R、G、B和alpha通道总共要占用4byte的空间。如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存。手机的内存通常很小,特别是Android设备还要给各个应用分配内存。在某些设备上,分给Facebook App的内存仅仅有16MB。一张图片就要占据其内存的十分之一。 @@ -127,7 +128,4 @@ DraweeViews 的功能不多,但都是至关重要的。他们监听Android的Vie 壁画是绘画技术,几个世纪以来一直受到世界各地人们的欢迎。我们许多伟大的艺术家使用这种名字,从意大利文艺复兴时期的大师拉斐尔到壁画艺术家斯里兰卡。我们并不是假装达到这个伟大的水平,我们真的希望Android开发者能像我们当初享受创建这个开源库的过程一样,非常享受的使用它。 ##更多 -[Fresco中文文档](http://fresco-cn.org/) - -## 原文链接 -[Introducing Fresco: A new image library for Android](https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/) \ No newline at end of file +[Fresco中文文档](http://fresco-cn.org/) \ No newline at end of file From 3e030b6871b134f498d50c0b91f9fdf63479503e Mon Sep 17 00:00:00 2001 From: Joker Date: Thu, 2 Apr 2015 13:57:07 +0800 Subject: [PATCH 13/14] fixed typo --- .../readme.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" "b/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" index 5eb8384a..0dfbe830 100644 --- "a/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" +++ "b/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" @@ -57,7 +57,7 @@ Flow 将一个应用分成一个逻辑上的 Screen组合,Screen不是任何 我们应用中的每一个Activity将会成为一个 Flow 对象,Flow对象在返回栈中保存了 Screen 的记录,和 Activity 或者 FragmentManager 的返回栈有些类似,通过这样的设计允许我们在 Screen 之间通过简单地实例化就可以轻松的切换,而不需要在应用中包含很多Activity。这里有一小部分 Activity(最好是一个)来持有这些 Screen。他们之间的关系下图类似: ![screen](http://www.bignerdranch.com/img/blog/2015/02/screen.png) -我们我们想切换到一个新的 Screen,我们只需简单地实例化这个 Screen,并且告诉我们 Flow 对象帮助我们切换为这个 Screen。除此以外,正如我们所期待的,Flow 被实例化后也会实现 goBack() 和 goUp() 方法。然而,许多开发者都把 Java 中的 goto 语句看作洪水猛兽,但事实上 Java 中的 goto 语句并没有它听起来那么恐怖。 +如果我们想切换到一个新的 Screen,我们只需简单地实例化这个 Screen,并且告诉我们 Flow 对象帮助我们切换为这个 Screen。除此以外,正如我们所期待的,Flow 被实例化后也会实现 goBack() 和 goUp() 方法。然而,许多开发者都把 Java 中的 goto 语句看作洪水猛兽,但事实上 Java 中的 goto 语句并没有它听起来那么恐怖。 ![flow](http://www.bignerdranch.com/img/blog/2015/02/flow.png) 从本质上看,Flow 的作用仅仅是在 App 中告诉我们将要切换到哪一个 Screen。而这样设计的好处在于,Flow 通过这样的设计让我们能够方便地在我们定义的各种不同的自定义 View 中切换,并使我们免受在 Activity 或 Fragment 需要考虑的种种麻烦,让我们把注意力都集中在处理 View上。Flow 为我们创造了一个简单,方便,以 View 为中心的应用架构。 From 74d9a40f54f18be1b9c82e5b4cfc2c9772c85adb Mon Sep 17 00:00:00 2001 From: Chaos <437700255@qq.com> Date: Thu, 2 Apr 2015 17:10:32 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readme.md" | 9 --------- 1 file changed, 9 deletions(-) diff --git "a/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" "b/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" index 0dfbe830..3e9eb5ed 100644 --- "a/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" +++ "b/androidweekly/Square \345\274\200\346\272\220\345\272\223Flow\345\222\214Mortar\347\232\204\344\273\213\347\273\215/readme.md" @@ -84,13 +84,6 @@ Presenter 是一个拥有简单生命周期和伴随其生命周期的 Bundle 完全没有 Fragment 那样复杂的生命周期,这可不是我吹的! -There are a lot of moving parts and new terms and classes and all sorts of room for confusion. So in sum, we have the following pieces of the puzzle: - -- Screen: A particular location in the application’s navigation hierarchy -- Blueprint: A section of an application with its own Dagger module -- Presenter: A View-controller object -- Custom Views: Views defined by Java and usually some XML - 文章写到这里,你会发现在 Flow 和 Mortar 中有许多发生改变的部分,新的术语和类,还有新的使用规范,这难免会让人一头雾水。所以为了方便大家的理解,总的来说,我们需要重视的是下面几个部分: - Screen: 在应用导航层次结构中的一个特殊存在,用来代表我们视图的对象 @@ -104,8 +97,6 @@ Here’s what our final Mortar and Flow architecture looks like: ![](https://www.bignerdranch.com/img/blog/2015/02/mortar-and-flow.png) -Instead of sticking with Model View Controller, the architecture has morphed into more of a Model View Presenter style. The big difference concerns the handling of runtime configuration changes like rotation. In MVC, our Controller (Activities and Fragments) will be destroyed alongside our Views, whereas in MVP, only our View will be destroyed and recreated. Nifty. - 抛弃了对 MVC 模式的执念,这个架构在完成之后变得更像 MVP 模式。这样巨大的转变使得新的架构需要关注如何处理应用在运行时配置信息改变的问题,例如:旋转。在 MVC 模式中,我们的控制器(Activity 和 Fragment)会随着我们的 View 一起被杀死。然而,在 MVP 模式中,我们只有 View 被杀死,又在需要它的时候重现它。挺有趣的对吧?