├── ActionBarNavigation ├── Prerequisites.md └── README.md ├── ActionModes └── README.md ├── ActivitiesandTheirLifecycles ├── ApplicationTranscedingtheActivity.md ├── AsynchronicityandResults.md ├── CreatingYourSecondActivity.md ├── Life,Death,andYourActivity.md ├── PonderingParcelable.md ├── README.md ├── RecyclingActivities.md ├── Schroedinger'sActivity.md ├── TheCaseoftheInvisibleActivity.md ├── UsingImplictIntent.md ├── WalkingThroughtheLifecycle.md ├── Warning!ContainsExplictIntents.md ├── WhenActivitiesDie.md └── extra!extra!.md ├── AdapterViewsAndAdapters └── README.md ├── AdvancedListViews └── README.md ├── AndroidandProjects ├── CommonConcepts.md ├── ProjectandAndroidStudio.md ├── README.md └── StarterProjectGenerators.md ├── AudioPlayback ├── GetYourMediaOn.md ├── MediaPlayerForAudio.md ├── OtherWaysToMakeNoise.md ├── Prerequisites.md └── README.md ├── AudioRecording ├── Prerequisites.md ├── README.md ├── RawAudioInput.md ├── RecordingbyIntent.md ├── RecordingtoFiles.md ├── RecordingtoStreams.md └── RequestingtheMicrophone.md ├── BasicWidgets ├── ACommandingButton.md ├── AssigningLables.md ├── CommonConcepts.md ├── FOGFOOC.md ├── FleetingImages.md ├── MoreCommonConcepts.md ├── README.md └── VisittheTrails.md ├── ChoosingYourDevelopmentToolchain ├── C-LBuildviaGradleforAndroid.md ├── IDEs...AndThisBook.md ├── README.md ├── WhatWeAreNotCovering.md ├── YetOtherAlternatives.md ├── androidstudio.md ├── eclipse.md └── intelli_idea.md ├── ContentsofAndroidProjects ├── ProjectsandthisBook.md ├── README.md ├── TheContentsofanAndroidStudioProject.md ├── TheContentsofanEclipseProject.md ├── WhatYouGet,InGeneral.md └── WhatYouGetOutOfIt.md ├── CustomDrawables ├── Prerequisites.md └── README.md ├── DealingWithThreads ├── AlternativestoAsyncTask.md ├── AndNow,TheCaveats.md ├── AsyncingFeeling.md ├── EventBuses.md ├── GettingtotheBackground.md ├── README.md ├── TheMainApplicationThread.md └── VisittheTrails!.md ├── EventBusAlternatives └── README.md ├── FindingandEliminatingJank └── README.md ├── FoucusOnNDK ├── Prerequisites.md ├── README.md └── TheRoleoftheNDK.md ├── GettingAroundAndroidStudio ├── AccessingAndroidTools.md ├── AndroidStudioandReleaseChannels.md ├── NavigatingTheProjectExplorer.md ├── README.md ├── RunningProjects.md ├── ViewingOutput.md └── VisittheTrails.md ├── GradleandDependencies ├── APropertyofTransitive.md ├── APropertyofTransitiveDependencies.md ├── ATaleofTwoDenpendenciesClosures.md ├── CreatingAndroidJARsfromGradle.md ├── DenpendingUponanAndroidLibraryProject.md ├── Dependencies.md ├── DependenciesByBuildType.md ├── DependenciesByFlavor.md ├── DependenciesandtheProjectStructureDialog.md ├── DependingUponArtifacts.md ├── DependingUponNDKBinaries.md ├── DependingUponSubProjects.md ├── DependingUponaJAR.md ├── ExaminingSomeCWACBuilds.md ├── PrerequisitesandWarning.md └── README.md ├── GradleandEclipseProject ├── CreatingYourGradleBuildFile.md ├── ExaminingtheGradleFile.md ├── Legacy.md ├── PrerequisitesandWarnings.md └── README.md ├── GradleandTasks ├── KeyBuild-RelatedTasks.md ├── README.md └── Results.md ├── GradleandtheNewProjectStructure ├── AddingBuildTypes.md ├── AddingProductFlavorsandGettingBuildVariants.md ├── ConfiguringtheStocksBuildTypes.md ├── CreatingaProjectintheNewStructure.md ├── DoingtheSplits.md ├── Falvors,Build,andtheProjectStructureDialog.md ├── ObjectivesoftheNewProjectStructure.md ├── PrerequisitesandWarnings.md ├── README.md ├── RevisitingtheLegacyGradleFile.md ├── Terminology.md ├── WhattheNewProjectStructureLooksLike.md └── WokingwiththeNewProjectStructureinAndroidStudio.md ├── InternetAccess ├── DIYHTTP.md ├── HTTPviaDownloadManager.md ├── README.md ├── SSL.md ├── UsingHTTPClientLibraries.md ├── UsingThird-PartyJARs.md ├── VisittheTrails.md └── WhatAboutHttpClient?.md ├── IntroducingGradleandTheManifest ├── ExaminingtheGradleFiles.md ├── GradleEnvironmentVariables.md ├── GradleTheBigQuestions.md ├── IntroducingtheManifest.md ├── LearningMoreAboutGradlle.md ├── ObtainingGradle.md ├── OtherGradleItemsofNote.md ├── README.md ├── TheRestOftheManifest.md ├── ThingsInCommonBetweenTheManifestandGradle.md ├── VersionsofGradleandGradleforAndroid.md ├── VisittheTrails.md └── Where'sTheGUI.md ├── JUnitandAndroid └── README.md ├── KeyAndroidConcepts ├── AndroidApplications.md ├── AndroidDevices.md ├── Don'tBeScared.md └── README.md ├── MiscellaneousNetworkCapabilities ├── DownloadingFiles.md ├── Prerequisites.md └── README.md ├── Preface ├── AbouttheAPKEdition.md ├── AbouttheUpdates.md ├── Acknowledgment.md ├── CC&42FG.md ├── ExendingYourWarescription.md ├── README.md ├── SourceCodeandItsLicense.md ├── TheBook'sStructure.md ├── TheTrails.md ├── Warescription.md ├── WelcometotheBook.md └── WhatsNewInVersion7.3.md ├── README.md ├── RecyclerView ├── ATrivialList.md ├── AdapterViewanditsDiscontents.md ├── ChangingtheContents.md ├── DividerOptions.md ├── EnterRecyclerView.md ├── Grids.md ├── HandlingClickEvents.md ├── MutableRowContents.md ├── OtherBitsofGoodness.md ├── Prerequisites.md ├── README.md ├── TheMarchoftheLibraries.md ├── TheOrderofThings.md ├── VaryingtheItems.md └── WhatAboutCursors.md ├── RequestingPermissions └── README.md ├── ResourceSetsandConfigurations ├── API-VersionedResources.md ├── AndNow,aWordFromtheAndroidProjectView.md ├── BlockingRotations.md ├── ChoosingTheRightResource.md ├── ConfigurationsandResourceSets.md ├── CopingwithComplexity.md ├── DefaultChangeBehavior.md ├── README.md ├── ScreenSizeandOrientation.md ├── StateSavingScenarios.md ├── What'saConfigurationAndHowDoTheyChange.md └── YourOptionsforConfigurationChanges.md ├── ServicesandtheCommandPattern └── README.md ├── SomeWordsAboutResource ├── Dimensions.md ├── GotthePicture.md ├── README.md ├── StringTheory.md └── TRTSNBNY.md ├── Summary.md ├── SwipingwithViewPager ├── Indicators.md ├── PagingFragments.md ├── PagingOtherStuff.md ├── PiecesofaPager.md ├── README.md └── SwipingDesignPattern.md ├── TheActionBar ├── ActionBarsLiveinLivingColor.md ├── ApplyingtheResource.md ├── BarHopping.md ├── DefiningtheResource.md ├── MENUKey,WeHardlyKnewYe.md ├── README.md ├── RespondingtoEvent.md ├── SettingtheTarget.md ├── TheRestoftheSampleActivity.md ├── VisittheTrails.md ├── YetAnotherHistoryLesson.md └── YourActionBarOptions.md ├── TheAndroidUserInterface ├── DissectingtheActivity.md ├── TheActivity.md └── UsingXML-BasedLayouts.md ├── TheDataBindingFramework ├── ObservablesandUpdatingtheBinding.md ├── OtherFeaturesofNote.md ├── Prerequisites.md ├── README.md ├── TheBasicSteps.md ├── TheBindingExpressionLanguage.md ├── TheExtendedLayoutResource.md └── TheWhatNow.md ├── TheLoaderFramework └── README.md ├── TheMediaStoreProvider └── README.md ├── TheTacticsofFragments ├── FragmentsWithinFragments.md ├── FragmentsandMultipleActivity.md ├── FragmentsandtheActionBar.md ├── README.md ├── TheFragmentLifecycleMethod.md ├── TheSixQuestions.md ├── WhereYouGetYourFragmentFrom.md ├── YourFirstDynamicFragment.md └── YourFirstFragment.md ├── TheTheoryofWidgets ├── README.md ├── Size,Margins,andPadding.md ├── TheAbsolutePositioningAnti-Pattern.md ├── TheThemeofThisSectionThemes.md ├── WhatAreContainers?.md └── WhatAreWidgets?.md ├── TheWebViewWidget └── README.md ├── Tutorial#1-InstallingtheTools ├── InOurNextEpisode.md ├── README.md ├── Step#1-CheckingYourHardwareRequirements.md ├── Step#2-SettingUpJavaand32-BitLinuxSupport.md ├── Step#3-InstalltheDeveloperTools.md └── Step#4-IntalltheSDKsandAdd-Ons.md ├── Tutorial#2-CreatingaStubProject ├── AboutOurTools.md ├── AboutOurTutorialProject.md ├── AbouttheRestoftheTutorials.md ├── InOurNextEpisode.md ├── README.md ├── Step#1CreatingtheProject.md ├── Step#2SetUptheEmulator.md ├── Step#3SetUptheDevice.md └── Step#4RunningtheProject.md ├── Tutorial#3-ChangingOurManifest ├── InOurNextEpisode.md ├── README.md ├── SomeNotesAboutRealtivePaths.md ├── Step#1SupportingScreens.md └── Step#2AddingOurMinimumandTargetSDKVersions.md ├── Tutorial#4-AdjustingOurResources ├── InOurNextEpisode.md ├── README.md ├── Step#1ChangingtheName ├── Step#2ChangingtheIcon └── Step#3RunningtheResult ├── UsingPreferences └── README.md ├── WorkingwithLibraryProjects ├── CreatingaLibraryProject.md ├── LibraryProjectsandtheManifest.md ├── LimitationsofLibraryProjects.md ├── Prerequisites.md ├── README.md └── UsingaLibraryProject,PartII.md └── WritingandUseParcelables └── README.md /ActionBarNavigation/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 理解这章需要你已经读过了核心章回,特别是动作栏那一章。 4 | 5 | -------------------------------------------------------------------------------- /ActionBarNavigation/README.md: -------------------------------------------------------------------------------- 1 | ###动作栏导航 2 | 3 | 除了应用图标(又称左侧的图标),动作栏工具项,和溢出菜单之外,动作栏也支持一个导航区域。 4 | 这存在在应用图标的右侧以及工具栏项/溢出菜单的左侧。你可以: 5 | 6 | * 把标签放在这里,允许用户在你应用不同部分之间切换 7 | * 使用"列表导航",这会在这产生一个Spinner,同样也允许用户从一个地方切换到另一个地方 8 | * 放入其他自定义形式的导航,例如搜索区域 9 | 10 | 这章会分析如何使用这些东西,以及它们是如何和Android中的其它结构绑定起来的,特别是ViewPager。 11 | 12 | 注意:这章列出的标签和列表导航形式在Android 5.0中已经被标为废弃了。开发者被推荐使用其它技术来用于活动导航。 13 | 14 | -------------------------------------------------------------------------------- /ActionModes/README.md: -------------------------------------------------------------------------------- 1 | ## Action Modes 2 | 3 | 如果你在Android 3.0+设备上已经花费了大量的时间,你可能已经遇到了一个渴望知道的现象。 4 | 有时候,当你选择列表中一个项或者其它控件时,aciton bar魔术般地从它的常态转化成一个可以对你选择的 5 | 东西进行操作的样子: 6 | 7 | 好消息是这不是内置进Edittext的魔法。你可以通过“action mode",同样也可以让你的应用有这个 8 | 效果。 9 | 10 | 在本章中,我们会探索如何设置并响应action modes。 11 | 12 | 13 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/ApplicationTranscedingtheActivity.md: -------------------------------------------------------------------------------- 1 | ###应用:不只是Activity 2 | 3 | Activity是从一个名叫Context的的类继承而来的。许多我们在我们activity上调用的方法,像startActivity()就是从Context继承而来的。 4 | 5 | 但是,activity不是Context唯一相关的子类。例如,之后我们会看到Service。并且有时候我们会看到空白的Context对象,例如在我们在之后涵盖到BroadcastReveicer的时候。 6 | 7 | 另一个需要注意的Context是Application。当应用被启动的时候一个Application的实例被创建了。Application实例是一个天然单例,在我们的进程中应该确切只有一个Application实例。 8 | 9 | 通常来说,这个单例是Application本身的实例。但是,如果我们想的话我们可以子类化Application,然后包含一个我们的自定义application类到manifest上元素的android:name属性上。然后,当Android启动我们的应用的时候, 10 | 它会创建一个我们所指派的Application子类,而不再是创建一个普通的Application实例。 11 | 12 | 在任意Context对象上调用getApplicationContext()的时候,我们都能够取得Application对象。getApplication() 13 | 会返回一个Context;如果我们需要引用我们所指定的Application子类,我们就需要向下转型返回的Context到合适的类型。 14 | 15 | 在Android应用中,我们有一些能够使用Application的方法。 16 | 17 | 第一点,如果我们需要在一个静态数据成员中持有一些其它对象,并且另外的对象是需要一个Context的话,我们就想要它使用Application,而不是Acticity,Service等。因为Application是一个单例,它实际上是“预先泄露的”。我们不能以某种方式让另一个非直接的静态变量应用它从而造成进一步的泄露。相比之下,假定我们有一个保存在activity的静态数据成员。现在,当Activity被摧毁的时候,它(和所有它持有的,像控件和监听器)不能垃圾回收。这就代表了内存泄露。 18 | 19 | 你可以进一步让Application管理这个静态数据,而不是使用多个独立的单例。这个方法既有优点又有缺点,但是总体来说,Google对这个方法并不感冒。话虽如此,在Application被实例haunted之后onCreate()很快就被调用了,并且你的Application子类可以重载这个方法并使用它来初始化一些全局变量。 20 | 21 | 但是,尽管Java文档指出Application上有一个表明当应用离开并且我们的进程被终止了onTerminate()方法,但是实际上这个方法从没有被调用过。 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/AsynchronicityandResults.md: -------------------------------------------------------------------------------- 1 | ###同步和结果 2 | 3 | 注意,startActivity()是同步的。在你的返回应用主线程控制权给Android之后,另一个activity才会显示出来。 4 | 5 | 通常来说,这不是很大的问题。但是,有些时候一个activity可能启动了另一个,其中第一个activity想知道一些来自 6 | 第二个activity的结果。例如,第二个activity可能是某种选择,允许用户选择一个文件或一个联系人或一首歌或这个其他的, 7 | 并且第一个activity需要知道用户选择了什么。使用同步的startActivity(),我们明显是不可能从startActivity()本身获取某种类型的返回结果。 8 | 9 | 为了处理这个情形,还有一个单独的startActivityForResult()方法。虽然它依然是同步的,它允许新启动的activity提供一个结果(通过一个setResult()方法),这个结果通过onActivityResult()方法传送到了最初的activity。我们会在之后一章中更为详细地分析startActivityForResult()。 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/Life,Death,andYourActivity.md: -------------------------------------------------------------------------------- 1 | ###你的Activity的生死 2 | 3 | 当activity在如上四个状态之间切换的时候,Android会在你的activity中进行回调。 4 | 5 | 注意对于所有这些,你应该向上链接并调用父类的这个方法的版本,或者Android会抛出一个异常。 6 | 7 | 8 | ####onCreate()和onDestory() 9 | 10 | 我们已经在我们所有的例子中的Activity子类中实现了onCreate()方法。这个方法会在以下两个主要情形中 11 | 被带调用: 12 | 13 | * 当activity首次被启动(例如,由于系统重启),onCreate()被调用的时候会传入null参数。 14 | * 如果activity已经处于运行状态了并且你的activity设置成基于不同的设备状态会有不同的资源(例如, 15 | 水平对竖直),你的activity会被重新创建并且onCreate()会被调用。我们会在这本书稍后内容更加详细地 16 | 讨论。 17 | 18 | 不管activity如何被使用,这里是你初始化你的用户界面并设置所有需要立即完成的事情的地方。 19 | 20 | 在生命周期的另一端,当activity被关闭的时候onDestroy()可能会被调用,比如因为activity调用了 21 | finish()方法(这个方法会结束activity)或者用户按下了返回键。因此,onDestory()方法是用阿里清理和释放 22 | 你从onCreate()方法中获取的资源,此外要确保所有你在生命周期方法之外启动的东西被中断了,例如后台线程。 23 | 24 | 记住,尽管如此,onDestory()方法可能不被调用。这可能在一些情形下发生: 25 | 26 | * 你的应用因没有处理的异常崩溃了 27 | * 用户强制中断了你的应用,例如通过设置应用。 28 | * Android有着释放内存的迫切需求(例如,处理一个打进来的电话),想要中止你的进程,并且没有时间去调用所有的 29 | 生命周期方法。 30 | 31 | 因此,onDestory()很有可能被调用,但是不能保证的。 32 | 33 | 34 | 此外,记住onDestory()的调用可能花费一段很长的时间。如果用户按下返回按钮来结束前台activity,onDestory()很快就会调用。但是如果,用户按下HOME按钮来到了主界面,你的activity不会直接被摧毁。直到Android决定优雅地结束你的进程的时候,onDestory()才会被调用。并且这个时间可能是几秒钟,几分钟,甚至几个小时。 35 | 36 | ####onStart(),onRestart(),和onStop() 37 | 38 | 一个activity能够来到前台,要么是因为它是首次被启动的,或者是因为它被遮盖之后被带回到了前台( 39 | 例如,被另一个activity,被一个打进来的电话)。 40 | 41 | onStart()方法会在如上两种情形中被调用。onRestart()方法会在activity已经被中断然后重新启动的时候 42 | 被调用。 43 | 44 | 反过来说,onStop()在activity将要中断的时候被调用。它同样可能没有被调用,和onDestory()没有被调用的原因一样。 45 | 但是,onStop()通常在activity不可见之后相当快的时间内就被调用了,所以onStop()被调用的可能性比onDestory()还要高。 46 | 47 | 48 | ####onPause()和onResume() 49 | 50 | onResume()方法在你的activity来到前台之前被调用,要么在初始化启动之后,要么是从终止状态 51 | 重新启动,要么在来电被清空之后。这是在你的activity上,刷新UI的一个绝佳地方。例如,你正在从一个服务拉取 52 | 一些改变信息(例如订阅的新条目),onResume()同样是一个刷新当前视图的很好的时机,如果适用的话,启动一个后台线程 53 | 去更新视图(例如,通过一个Handler)。 54 | 55 | 反过来说,所有接管用户输入的-大部分是在另一个activity的驱动下-会导致你的onPause()被调用。在这里, 56 | 你应该撤销所有你在onResume()中所做的事情,例如终止后台线程,释放所有你获取的独占资源(例如,相机),和诸如此类的。 57 | 58 | 一旦onPause()被调用之后,Android具有了在任意时间杀死你的activity的进程的权利。因此,你应该不能指望接收 59 | 更多的事件。 60 | 61 | 那么,所以onPause()和onStop()直接的区别是什么呢?如果一个activity来到前台并充满了屏幕, 62 | 你当前的前台activity的onPause()和onStop()会被调用。但是如果,一个activity来到前台但是没有充满 63 | 屏幕,只有你当前的前台activity的onPause()会调用,因为它仍然是可见的。 64 | 65 | ####凑成对 66 | 67 | 如果你在onCreate()中初始化了某些东西,在onDestory()中把它清理掉。 68 | 69 | 如果你在onStart()中初始化了某些东西,在onStop()中把它清理掉。 70 | 71 | 如果你在onResume()中初始化了某些东西,在onPause()中把它清理掉。 72 | 73 | 换句话说,凑成对。例如,不要在onStart()中初始化了某些东西然后尝试在onPause()中进行清理,很多情形下onPause()可能被一系列地多次调用(例如,用户可能启动一个非全屏的activity,这会触发onPause()但没有触发onStop()和onStart())。 74 | 75 | 你要根据你的需要选择生命周期对方法。你可能决定你需要两对(例如,onCreate()/onDestory()和onResume()/onPause()).只要别搞混它们之间对应关系。 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/PonderingParcelable.md: -------------------------------------------------------------------------------- 1 | ###考虑Parcelable 2 | 3 | 就像以上提及到的,`Intent extras`不能处理任意的对象的。这是因为,大都时候,`Intent extras`是跨进程传递的。 4 | 即使你调用startActivity()来启动你自己的多个activity中的一个,请求从你的进程传递到核心系统进程然后在返回到 5 | 你的进程。同时`Intent extras`也传了过去。 6 | 7 | 8 | 因此,`Intent extras`需要是能够转换成一个二进制数组的东西,作为进程间通信的一部分处理传入的Intent对象。你也会看到在其他风格的Android IPC看到这个,例如远程服务。 9 | 10 | 但是,有两种方式你可以尝试,使你的对象以`Intent extras`的形式工作。 11 | 12 | 一种方式是在你的类上实现`Serializable`。这是经典的Java结构,设计成允许你的类的实例和你的实例所持有的序列化的对象,序列化到文件中然后之后从文件中读取出来。 13 | 14 | 15 | 另一种方式是在你的类上实现`Parcelable`。这是一种Android结构,这个结构和`Serializable`非常相似。但是,`Serializable`是为对象的持久化存储而设计的,可能几个月或者几年之后都可以从文件中读取回来。同样的,`Serializable`需要处理java代码上实现这些类的改变,并且同样也需要有着帮助转换旧的,保存过的对象到新的对象上的钩子。这就增加了开销。`Parcelable`只关心把对象转成二进制数据然后进行跨进程传递。它能够做出这个类定义在从对象转换成二进制和二级制转换回对象的过程中不会改变的简单化假定。作为结果,`Parcelable`在Android的跨进程使用方面比`Serializable`快。 16 | 17 | 如果你想要的话,你是欢迎在你自己的类上实现`Parcelable`的。除此之外,所有你在Adnroid Java文档中看到实现了`Parcelable`的类都能放进`Intent extras`中。所以,例如,Uri实现了`Parcelable`,那么你就能把Uri放进 18 | `Intent extras`。不是Android SDK的所有东西都是`Parcelable`的,但是一些像Uri的关键是`Parcelable`的。 19 | 20 | 21 | 更多`Parcelable`的细节,包括你如何在你的类上实现它,会在这本书之后内容出现。 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/README.md: -------------------------------------------------------------------------------- 1 | ##Activity们和它们的生命周期 2 | 3 | 一个Android应用会有多个互无关联的UI界面。例如,一个日历应用需要让用户浏览日历, 4 | 浏览单个事件的详情,编辑一个事件(包括添加一个新的),等等。并且在较小屏设备上,像大部分的 5 | 手机,你可能没有空间把所有这些一次性地挤在屏幕中。 6 | 7 | 为了解决这个问题,你可以有多个activity。你的日历应用可能有一个展示日历的activity,一个用作 8 | 添加或编辑时间,一个用作提供日历如何工作的设置,一个用作网上求助,等等。这些activity中的一些可能是你应用私有的, 9 | 但同时其它的可能被第三方启动,比如你的启动activity主屏幕上是可用的。 10 | 11 | 所有这些表明了你的多个activity中的其中一个有着启动其它activity的方法。例如,如果某人从查看日历的activity点击了一个事件,你可能想要为这个事件展示查看事件的activity。这就意味着,你需要以某种方式能够使查看事件的activity启动并且展示某一特定的事件(用户点击的那一个)。 12 | 13 | 这可以进一步分解成两种情形: 14 | 15 | * 你知道你所要启动的activity,可能是因为它是你应用中的另一个activity。 16 | * 你有着某个东西的引用(例如,一个网页),并且你想要你的用户能用它做些什么,但是你不知道有什么可选的操作。 17 | 18 | 这两种情形在这章中都会涵盖到。 19 | 20 | 此外,时常对你来说知道什么时候activity来到和离开前台是很重要的,因为这样你就可以自动保存或刷新数据,等等。这就是所谓的“activity生命周期”,并且我们也会在这章中详细分析它。 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/RecyclingActivities.md: -------------------------------------------------------------------------------- 1 | ###回收activity们 2 | 3 | 让我们假定我们有三个activity,分别叫做A,B和C.A基于一些用户输入启动了一个B的实例,并且稍后B通过一些更多的 4 | 用户操作启动了C的一个实例。 5 | 6 | 我们的“activity栈”现在是A-B-C,意味着如果我们从C按下返回键,我们就返回到了B,并且如果我们从 7 | B按下了返回键,我们返回到了A。 8 | 9 | 现在,让我们假定我们想从C导航回到A。例如,可能用户按下我们动作栏左侧的图标,我们想要返回到主界面activity,在我们的情形中就是A。如果C调用了startActivity(),指定了A,我们就以A-B-C-A这个activity栈告终了。 10 | 11 | 那是因为启动一个activity时,默认会创建一个新的这个activity的实例。那么,现在我们就有了两份独立的A拷贝。 12 | 13 | 有时候,这是所期望的行为。例如,我们可能有单个ListActivit通过层次数据集向下钻取数据,就像一个目录树。我们可能 14 | 选择保持启动同一个ListAcivity,但是带有不同的`extras`,来展示每一个层级。在这种情形中,我们会想要activity的独立实例,那样返回按钮就表现的就和用户所预期的一样。 15 | 16 | 但是,当我们导航回主界面activity,我们可能不会想要一个单独的A实例。 17 | 18 | 如何解决这个问题和导航到A之后的activity栈的样子有一点关系。 19 | 20 | 如果你想要的activity栈是B-C-A-那么已存在的A拷贝被带到了前台,但是B和C的实例就被留下了-然后你可以在使用 21 | startActicity()的时候添加FLAG_ACTIVITY_FEORDER_TO_FRONT到你的Intent。 22 | 23 | Intent i=new Intent(this,HomeActivity.class); 24 | i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 25 | startActivity(i); 26 | 27 | 取而代之的,如果你想要的activity站仅仅是A-那么如果用户按下了返回键,他们就离开了你的应用-那么你会添加两个 28 | 标记:FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_SINGLE_TOP: 29 | 30 | Intent i=new Intent(this,HomeActivity.class); 31 | i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT|Intent.FLAG_ACTIVITY_SINGLE_TOP); 32 | startActivity(i); 33 | 34 | 这会结束栈中位于当前activity和你所启动的activity之前的activity,在我们的情形中,结束了C和B。 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/Schroedinger'sActivity.md: -------------------------------------------------------------------------------- 1 | ###薛定谔的Activity 2 | 3 | 一个activity,通常来说,在任何时间点会处于以下四种状态中的一种: 4 | 5 | 1.Active: activity被用户启动了,正在运行,并且处于前台。这是你用来思考你activity的操作的时候。 6 | 7 | 2.Paused: activity被用户启动了,正在运行,并且是可见的,但另外有个activity覆盖了部分屏幕。 8 | 在这个期间,用户可以看见你的activity但是可能不能和它进行交互。这是一个相对不常见的状态,因为大都数activity 9 | 是被设置成全屏的,没有一个让它们看起来像某种对话框的主题。 10 | 11 | 3.Stopped:activity被用户启动了,正在运行,但是它被其他启动的或切换到的activity挡住了。 12 | 13 | 4.Dead:活动被杀死了,可能是因为用户按下了返回按钮。 14 | 15 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/TheCaseoftheInvisibleActivity.md: -------------------------------------------------------------------------------- 1 | ###不可见Activity的情形 2 | 3 | 有时候,你会要一个没有UI的activity。 4 | 5 | 这是相当少见见的。大部分时候,它会是需要你有一个activity,但是没有真正要以传统的activity样式UI展示给用户的。 6 | 7 | 例如,主界面启动按钮只启动activity。但是,你可能你需要一个主界面启动器仅仅触发一些在后台完成的工作,可能会使用 8 | 一个service(就像这本书稍后内容会讨论的)。 9 | 10 | 你有两种设置不可见activity的方式,包括在元素上使用一个特定的android:theme值。 11 | 12 | 最高效的选择是使用Theme.NoDisplay。有了这个值,就设置UI而言就没有做任何工作。但是,关键限制是所有的工作 13 | 需要在onCreate()方法中完成,并且在那里你需要调用finish()去触发让activity被摧毁。多数情况下,这就能很好地工作。 14 | 15 | 有时候,你需要一个不可见的activity挂起几秒钟,可能是在他被摧毁之前,等待一些回调结果。使用Theme.NoDisplay仍然能够工作...但是只是在较老的Android设备上。在Android 6.0以及更高的版本上,使用Theme.Nodisplay而没有在onCreate()中调用finish()(或者,技术上来说,在onResume()之前)会使你的应用崩溃。 16 | 17 | 变通方案是使用Theme.Translucent.NoTitleBar。这个实际上分配了一个UI给你,但是把它设置成了一个透明的背景并且没有动作栏。用户可能感知到activity在那里-例如,它出现在概览屏上(又名最近任务列表)。也因为activity真的在那,用户可能不能和它所看到的进行交互,例如在底层的主屏幕上。但是,如果activity本身能很快地finish()自己,并且是和用户实时交互的(例如,展示展示一些系统对话框),你可能能够使用这个方法。 18 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/UsingImplictIntent.md: -------------------------------------------------------------------------------- 1 | ###使用隐式意图 2 | 3 | 显式Intent方式在启动你自己的activity的时候是很好工作的。 4 | 5 | 但是,你可能会启动来自操作系统或第三方应用的activity。在这些情形中,在你的项目中你没有代表其它activity的Java类,那么你就不能使用以类作为参数意图构造器。 6 | 7 | 取而代之的,你会使用"隐式"意图结构,它看起来就像网页的工作方式一样令人讨厌。 8 | 9 | 如果你做过任何Web应用的工作的话,你会意识到HTTP是基于附加到URI的动词的: 10 | 11 | * 我们想要GET这张图片 12 | * 我们想要POST这个脚本到控制器 13 | * 我们想要PUT这个倒REST资源 14 | * 等等 15 | 16 | Android的隐式意图模式差不多是相同的方式,只不过有更多的动词。 17 | 18 | 19 | 例如,你从某个地方获取了经纬度(例如,微博的内容,短信消息的内容)。你决定你要在地图上展示这些坐标。你有很多方式可以直接嵌入Google地图到你的应用,并且会在之后的章回看到底怎么做-但是展示复杂的并且是以用户想要使用Google地图为前提的。如果我们可以创建通用类型的请求,“你好,Android,展示一个显示这个坐标到地图上的activity”。 20 | 21 | 或者,在一个更为简单的情形中,我们获取到了来自某个来源的网页URL(例如,Web服务调用)并且我们想要在这页上代开一个浏览器。这会在Actities/LauncheWeb样例项目中进行举例说明。 22 | 23 | 其中,我们有一个使用了一个包含一个EditText控件和Button的布局的LauchDemo Activity。 24 | 25 | 26 | 27 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 按钮被绑定到了activity本身上的一个showMe()方法,在这个方法中我们带出了浏览一个输入到EditText的URL的浏览器。 50 | 51 | package com.commonsware.android.activities; 52 | 53 | import android.app.Activity; 54 | import android.content.Intent; 55 | import android.net.Uri; 56 | import android.os.Bundle; 57 | import android.view.View; 58 | import android.widget.EditText; 59 | 60 | public class LaunchDemo extends Activity { 61 | @Override 62 | public void onCreate(Bundle icicle) { 63 | super.onCreate(icicle); 64 | setContentView(R.layout.main); 65 | } 66 | 67 | public void showMe(View v) { 68 | EditText url=(EditText)findViewById(R.id.url); 69 | 70 | startActivity(new Intent(Intent.ACTION_VIEW, 71 | Uri.parse(url.getText().toString()))); 72 | } 73 | } 74 | 75 | 76 | 这里,我们取得了URL并通过调用Uri.parse把它转换成Uri。然后,我们可以使用一个叫做ACTION_VIEW的动作去尝试展示所要的网页。 77 | 78 | 79 | 当启动的时候,展现在用户面前的是我们的数据入口表单: 80 | 81 | 我们可以填入一个URL: 82 | 83 | 如果设备上有以https:模式响应ACTION_VIEW意图的应用,点击“ShowMe!”按钮之后,会带出那个应用,很可能是一个网页浏览器: 84 | 85 | 在之后章回中,我们将会讨论如果没有处理这个意图的情况发生,或有多个应用可以进行处理的情况。 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/WalkingThroughtheLifecycle.md: -------------------------------------------------------------------------------- 1 | ###漫步生命周期 2 | 3 | 为了知道这些多个生命周期方法是什么时候被调用的,让我们分析下Activities/Lifecycle这个样例项目. 4 | 5 | 除了我们的两个activity不是直接继承Activity之外,这个项目是和Activities/Extras项目一样的。 6 | 取而代之的我们引进了一个LifecycleLoggingActivity作为基类并让我们的activity继承它: 7 | 8 | package com.commonsware.android.lifecycle; 9 | 10 | import android.app.Activity; 11 | import android.os.Bundle; 12 | import android.util.Log; 13 | 14 | public class LifecycleLoggingActivity extends Activity { 15 | @Override 16 | public void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | 19 | Log.d(getClass().getSimpleName(), "onCreate()"); 20 | } 21 | 22 | @Override 23 | public void onRestart() { 24 | super.onRestart(); 25 | 26 | Log.d(getClass().getSimpleName(), "onRestart()"); 27 | } 28 | 29 | @Override 30 | public void onStart() { 31 | super.onStart(); 32 | 33 | Log.d(getClass().getSimpleName(), "onStart()"); 34 | } 35 | 36 | @Override 37 | public void onResume() { 38 | super.onResume(); 39 | 40 | Log.d(getClass().getSimpleName(), "onResume()"); 41 | } 42 | 43 | @Override 44 | public void onPause() { 45 | Log.d(getClass().getSimpleName(), "onPause()"); 46 | 47 | super.onPause(); 48 | } 49 | 50 | @Override 51 | public void onStop() { 52 | Log.d(getClass().getSimpleName(), "onStop()"); 53 | 54 | super.onStop(); 55 | } 56 | 57 | @Override 58 | public void onDestroy() { 59 | Log.d(getClass().getSimpleName(), "onDestroy()"); 60 | 61 | super.onDestroy(); 62 | } 63 | } 64 | 65 | LifecycleLoggingActivity重载了以上提到的生命周期方法并发表了一个指示什么被调用了的调试行。 66 | 67 | 当我们首次启动应用的时候,我们的首批生命周期方法以我们所预期的顺序被调用了: 68 | 69 | 04-01 11:47:21.437:D/ExplictIntentsDemoActivity(1473):onCreate() 70 | 71 | 04-01 11:47:21.827:D/ExplictIntentsDemoActivity(1437):onStart() 72 | 73 | 04-01 11:47:21.827:D/ExplictIntentsDemoActivity(1437):onResume() 74 | 75 | 如果我们点击了首个activity上的按钮来启动第二个activity,我们获得了: 76 | 77 | 04-01 11:47:54.776: D/ExplictIntentsDemoActivity(1473):onPause() 78 | 79 | 04-01 11:47:54.877: D/OtherActivity(1473):onCreate() 80 | 81 | 04-01 11:47:54:947: D/OtherActivity(1473):onStart() 82 | 83 | 04-01 11:47:54:974: D/OtherActivity(1473):onResume() 84 | 85 | 04-01 11:47:55.347: D/ExplictIntentsDemoActivity(1473):onStop() 86 | 87 | 注意我们的首个activity是在第二个activity启动之前被暂停的,并且首个activity的onStop()方法被延迟到了第二个 88 | activity出现之后。 89 | 90 | 91 | 如果我们在第二个activity上按下了返回按钮,返回到首个activity,我们看到了: 92 | 93 | 04-01 11:48:54.807: D/OtherActivity(1473):onPause() 94 | 95 | 04-01 11:48:54.857: D/ExplictIntentsDemoActivity(1473):onRestart() 96 | 97 | 04-01 11:48:54.857: D/ExplictIntentsDemoActivity(1473):onStart() 98 | 99 | 04-01 11:48:54.857: D/ExplictIntentsDemoActivity(1473):onResume() 100 | 101 | 04-01 11:48:55:257: D/OtherActivity(1473):onStop() 102 | 103 | 04-01 11:48:55:257: D/OtherActivity(1473):onDestroy() 104 | 105 | 注意到,进入屏幕发生在离开屏幕的activity的onPause()和的onStop()方法之间。也注意到 106 | 在onStop()之后onDestroy()马上就被调用了,因为activity是通过返回按钮结束掉的。 107 | 108 | 109 | 如果我们按下了HOME按钮,让主界面activity来到前台,我们看到了: 110 | 111 | 04-01 11:50:30.347 D/ExplictIntentsDemoActivity(1473):onPause() 112 | 113 | 04-01 11:50:32.227 D/ExplictIntentsDemoActivity(1473):onStop() 114 | 115 | 因为主界面做了它的展示工作,在onPause()和onStop()之间存在一个延迟。并且 116 | 没有onDestory(),因为应用仍在运行并且没有东西结束activity。终究,设备会终止我们的进程, 117 | 并且如果这是正常发生的,我们会看到onDestory()LogCat消息。 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/Warning!ContainsExplictIntents.md: -------------------------------------------------------------------------------- 1 | ###警告!包含显式意图! 2 | 3 | 一个意图封装了一个对Android作出的请求,用于让一些activity货其他receiver做一些事情。 4 | 5 | 如果你想要启动的activity是你自己的,你可能找到的最简单的方式就是创建一个显式的意图,命名你想要启动 6 | 的组件。例如,你可以在你的activity里创建一个这样的意图: 7 | 8 | new Intent(this,HelpActivity.class); 9 | 10 | 你会规定你想要启动的是HelpActivity.HelpActivity会需要在你的AndroidManifest.xml中有一个对应的 11 | 元素。 12 | 13 | 在Activities/Explict,ExplicitIntentDemoActivity有着一个绑定到按钮控件的onclick属性的showOther()方法。 14 | 这个方法会使用带有识别OtherActivity的显式意图的startActivity(): 15 | 16 | package com.commonsware.android.exint; 17 | 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.os.Bundle; 21 | import android.view.View; 22 | 23 | public class ExplicitIntentsDemoActivity extends Activity { 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.main); 28 | } 29 | 30 | public void showOther(View v) { 31 | startActivity(new Intent(this, OtherActivity.class)); 32 | } 33 | } 34 | 35 | 我们启动的activity显示了button: 36 | 37 | 点击按钮带出了另一个activity: 38 | 39 | 点击BACK会带我们回到第一个activity。在这一方面,Andorid中的BACK按钮就和你浏览器 40 | 中的返回按钮差不多。 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/WhenActivitiesDie.md: -------------------------------------------------------------------------------- 1 | ###当Activity死亡的时候 2 | 3 | 那么,什么能除掉一个activity呢。什么能触发导致onDestory被调用的事件链呢? 4 | 5 | 首要的,当用户按下返回按钮的时候,前台activity会被摧毁,在用户的导航流中控制权会返回到 6 | 前一个activity。 7 | 8 | 你可以从activity调用finish()来完成同样的事情。这主要是因为一些其他UI操作会指示用户 9 | 离开activity。但是,请不要人为地添加你自己的“exit”,"quit"或其他的菜单项或按钮到你的 10 | activity上,只允许用户使用常规的Android导航选项,例如返回按钮。 11 | 12 | 如果你的activity没有一个在前台了,你的应用进程是被终止进而释放内存的候选者。就像之前提及到的,在这些情形中,Android可能会调用也可能不会调用onDestory()方法(onPause()和onStop()会在你的activity离开前台的时候被调用)。 13 | 14 | 如果用户导致设备经历了一次“配置改变,例如横竖屏切换”,Android的默认行为是摧毁你当前的前台activity 15 | 然后在它的位置创建一个崭新的activity。我们会在稍后一章中涵盖到这个内容。 16 | 17 | 并且,如果你的activity有一个没有处理的异常,你的activity会被摧毁,尽管如此Android不会在activity上调用任何 18 | 方法,因为它认为你的activity处于不稳定状态中。 19 | 20 | -------------------------------------------------------------------------------- /ActivitiesandTheirLifecycles/extra!extra!.md: -------------------------------------------------------------------------------- 1 | ###Extra!Extra! 2 | 3 | 有时候,你可能想把一些数据从一个activity传到另一个activity。例如,我们可能有一个展示 4 | 我们模型对象集合(例如,书籍)的ListActivity并且我们有着一个用来单独展示特定模型对象的DetailActivity。 5 | DetailActivity需要以某种方式知道要展示哪个模型对象。 6 | 7 | 一种完成这个工作的方式是通过意图的`extras`。 8 | 9 | Intent上有一系列的putExtra()方法,来允许你把键/值对数据打包进Intent中。虽然你不能传入任意的对象, 10 | 大都数的基本数据类型是支持的,例如字符串和一些列表类型。下一节内容,会分析更多关于什么能放进Intent的extra。 11 | 12 | 所有的activity都可以调用getIntent()来取得用来把它启动的意图,然后可以调用多种形式的get...Extra(...指示的是数据类型)来获取所有打包的`extra`。 13 | 14 | 例如,让我们看下Activities/Extras这个样例项目. 15 | 16 | 这几乎是之前这章的Activities/Explict的一个复制版。但是,这次,我们的第一个 17 | activity会传递一个extra给第二个: 18 | 19 | package com.commonsware.android.extra; 20 | 21 | import android.app.Activity; 22 | import android.content.Intent; 23 | import android.os.Bundle; 24 | import android.view.View; 25 | 26 | public class ExtrasDemoActivity extends Activity { 27 | @Override 28 | public void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.main); 31 | } 32 | 33 | public void showOther(View v) { 34 | Intent other=new Intent(this, OtherActivity.class); 35 | 36 | other.putExtra(OtherActivity.EXTRA_MESSAGE, getString(R.string.other)); 37 | startActivity(other); 38 | } 39 | } 40 | 41 | 我们和之前一样创建了Intent,然后调用了putExtra(),提供了一个键(一个静态的叫做OtherActivity.EXTRA_MESSAGE字符串)和一个值(R.string.other字符串资源)。然后,只有这样,我们才能调用startActivity()。 42 | 43 | 我们修改的OtherActivity然后获取extra,同时inflate了TextView(通过findViewById())并把文本填充进去: 44 | 45 | package com.commonsware.android.extra; 46 | 47 | import android.app.Activity; 48 | import android.os.Bundle; 49 | import android.widget.TextView; 50 | 51 | public class OtherActivity extends Activity { 52 | public static final String EXTRA_MESSAGE="msg"; 53 | 54 | @Override 55 | public void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.other); 58 | 59 | TextView tv=(TextView)findViewById(R.id.msg); 60 | 61 | tv.setText(getIntent().getStringExtra(EXTRA_MESSAGE)); 62 | } 63 | } 64 | 65 | 66 | 视觉上来说,结果是一样的。功能上来说,所展示的文本是从上一个activity传过来的。 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /AdapterViewsAndAdapters/README.md: -------------------------------------------------------------------------------- 1 | ## AdapterViews和Adapters 2 | 3 | 如果你想要用户从一些东西的集合中来选,你可以使用一串的RadioButton控件。但是,Android有着一系列 4 | 更为灵活的控件,在本书中被称作"选择控件"。 5 | 6 | 它们包括: 7 | * ListView,典型的列表框控件 8 | * Spinner,下拉列表 9 | * GridView,提供两个维度的列表 10 | * ExpandableListView,支持两级树结构的列表控件 11 | 12 | 等等。 13 | 14 | 按本质来说,它们是普通的控件。你可以在你的集成开发环境图形布局编辑器里的工具栏找到它们,并且可以把它们拖放进你认为 15 | 合适的位置。 16 | 17 | 关键是它们都有一个共同的父类:AdapterView,这么命名的原因是它们和实现Adapter接口来决定什么让用户选择的对象合作。 18 | 19 | ###适应环境 20 | 21 | 适配器是你的模型数据和在AdapterView中视觉表现之间的桥梁: 22 | 23 | * 适配器可能适配一个装货清单进一个视图然后作为ListView中的一行 24 | * 适配器可能适配一本书进一个视图然后作为GridView的一个单元 25 | * 等等 26 | 27 | Android已经备好了可以给你使用的若干适配器类,不同的适配器类适配不同的集合种类。(例如,数组和数据库查询的结果)。 28 | 如果你需要适配一个所有Android提供的适配类都不能匹配的数据集合的时候,Android也有一个作为你自己适配器实现基石的BaseAdapter类。 29 | 30 | ##TODO 31 | -------------------------------------------------------------------------------- /AdvancedListViews/README.md: -------------------------------------------------------------------------------- 1 | ## 高级ListViews 2 | 3 | 简陋的ListView是许多Android应用的主干。在手机屏幕上,屏幕可能被单个ListView占据,然后允许用户选择一些来查看更多详细(例如,选择一个联系人)。 4 | 在大屏上,ListView和选择项的详细内容可能是并排排列的,最小化用户在列表和详情切换的撑杆跳效果。 5 | 6 | 虽然我们已经在这本书的核心章节涵盖了ListView的基础知识,如果你选的话,可以做很多事让你的列表看起来更有意思-这章会涵盖一些这些技术。 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AndroidandProjects/CommonConcepts.md: -------------------------------------------------------------------------------- 1 | ###常见的概念 2 | 3 | 多种建立Android项目的方法中有一些共同元素。“Application Name” 是被用户看到的项目的最初始的名字。在你输入一个应用名的时候,项目名会对应应用名而自动填充,填充时把空格和其它非法的字符移除。当然,你可以按自己的方式进行更改。至于在Android Studio中,项目名也形成容纳项目的目录的名称。 4 | 5 | 包名指的是Java包名(例如:com.commonware.empulite)。这个包名在生成一些Java源代码的时候也会被使用,就像这本书之前提到的一样,包名也会作为这个包的唯一标识。 6 | 7 | 最小需要的SDK指的是向后支持Android的历史版本的有多久远。你在这定义的值越低,你所能运行的Android设备也就越多,但是你需要做更多的工作去测试你的应用时候真正支持这些设备。现如今,对新的开发来说,值为15最小需要的SDK是合理的,并且如果需要的话你可以选择较后的值。 8 | 9 | 目标SDK,粗略地讲,就是你编写这个应用代码时考虑的Andorid版本。通常来说,你会把这个设置成最近出来的Android API等级,然后在新的Android版本发布的时候并且在你为这些改变做好准备的时候进行更改。我们会在这本书中探索这个目标SDK的分支。 10 | 11 | "Compile With"(也叫作,“编译SDK”或者编译SDK版本)是你想要编辑通过的Android版本的类和方法。这个可以比最小需求SDK要信,并且通常较新。在较新设备运行较新版本的Android,你可能要利用一些新的特性,并且你会游荡在较旧设备上的代码来维持向后兼容。因此,通常你的编译SDK版本被设置成一个相对较新的版本,无疑地是一个足够新的来支持你所想要使用的AndroidSDK的所有类和方法的版本。注意要设置这个版本到API等级21或者更高,你将要需要使用Java7或者更高作为Java编译器。 12 | 13 | 主题是你的应用外观上的一般陈述,特别是就色彩方案而言。当前默认的(“Holo Light with Dark Action Bar”)意味着你的用户界面主体的文本是深色的以及背景是浅色的。除了顶部的动作栏,文本是浅色的背景是深色的。你可以创建你自己自定义的主题,重载这些常备主题一个的多样特性,来设置你们自己的色彩方案和样子。我们会在这本书之后的内容中进行探索。 -------------------------------------------------------------------------------- /AndroidandProjects/ProjectandAndroidStudio.md: -------------------------------------------------------------------------------- 1 | ###项目和Android Studio 2 | 3 | 你可能已经选择使用Android Studio作为你的集成开发工具。 4 | 5 | 使用Android Studio开发一个项目,你可以从简易编程工具创建一个新的项目,你可以从已存在的一个Android Studio复制到新的,或者你可以导入一个已存在的Android项目到AndroidStudio中。接下来的章节会回顾这些的必要步骤。 6 | 7 | ####创建一个新的项目 8 | 9 | 你可以从这两个地方中的一个创建项目 10 | 11 | 如果当你打开Android Studio的时候,你处于首次碰到的初始对话框,选择“Start a new Android Studio project”菜单按钮。 12 | 如果你处于Andorid Studio集成开发环境中,从主菜单选择File>Create Project 13 | 这就带来了新项目向导: 14 | 15 | 向导首页是你可以详细指明以下内容: 16 | 17 | * 应用名 18 | * 包名 19 | * 项目放置的文件夹 20 | 默认情况下,包名由两部分组成: 21 | 22 | 1.你在“CompanyDomain”区域详细指明的域名 23 | 24 | 2.包名,被转成的全部小写无空格和其他标点 25 | 26 | 如果这不是你想要的,点击建议包名右侧的小小的“Edit”链接,它现在允许你直接编辑包名: 27 | 28 | 点击“Next”让你来到让你指示创建项目的类型向导页,依据预期的设备类型(手机、平板、电视等等)以及最小所需SDK等级作出选择。 29 | 30 | 开发者启动Android仅仅需要勾选“Phone and Tablet”作为设备类型。默认的“Minimum SDK”值通常也是个好的选择,并且正如我们稍后再这部书中所看到的,它在你的项目中随时可以更改, 31 | 32 | 点击“Next”下一步让你来到向导第三页,在这里你可以选择让Android Studio创建初始化活动是基于什么模板: 33 | 34 | 这些模板中没有一个是特别好的,因为它们添加了大量的你可能完全将其替换掉的示例材料。“Empty Activity”是首次接触Android开发者的最优选项,仅仅因为它加了最少的东西。 35 | 36 | 如果你选择了除“Add No Activity”之外的选项,点击“Next”将带你来到一个给你提供关于活动如何创建的附加细节: 37 | 38 | 出现在这里的选项很大程度上取决于你前一页的选择。常见的选项包括“Activty Name”(活动的Java类名)以及“Layout Name”(包含你的活动用户界面的XML文件的基本名)。 39 | 40 | 点击“Finish”会生成你的项目文件。 41 | 42 | ####复制一个项目 43 | 44 | Android Studio项目只不过是文件目录,没有保存在其它地方的特别元数据(正如Eclipse中)。因此,赋值一个项目,仅仅需要复制它的目录。 45 | 46 | ####导入一个项目 47 | 48 | 你可以从以下两个地方中的一个导入项目 49 | 50 | * 如果当你打开Android Studio的时候,你处于首次碰到的初始对话框,选择“Import Project”菜单按钮。 51 | * 如果你处于Andorid Studio集成开发环境中,从主菜单选择File>New...>Import Project... 52 | 然后,选择项目要导入的目录。 53 | 54 | 现在发生的取决于项目的特性。如果对Android Studio的使用进行了设置,至少是Android的Gradle,Android Studio详细描述的文件会在项目目录。 55 | 56 | 但是,如果项目没有对Andorid Studio会Andorid的Gradle进行设置,但是有Eclipse项目文件(或至少有project.properties文件),你会被导向Eclipse导入向导。 57 | 58 | 向导的第一页是你详细说明Android Studio应该在哪复制这个项目的地方,因此它没有修改过初始目录的任何东西: 59 | 60 | 点击“Next”会带你来到一个你能对一些作用于导入项目代码的自动修复进行配置。这里的细节已经越过了我们这本书目前覆盖的范围。通常来说,默认的就很好。 61 | 62 | 点击“完成”会完成项目转换。Android Studio会打开一个import-summary.txt文件列出转换如何完成的一些详细内容。这时候,复制修改的项目已经能使用了。 63 | -------------------------------------------------------------------------------- /AndroidandProjects/README.md: -------------------------------------------------------------------------------- 1 | ##Android和项目 2 | 当你致力于创建一个Android应用的时候,你将在一个“项目”中去做。项目是一个包含你的源代码和像图片和UI定义的其它文件。你的集成开发环境和其它开发工具会获取你项目中的内容并生成一个Android应用(APK)作为输出。 3 | 4 | 开始一个项目的细节根据你所使用的集成开发环境会有不同,所以这章伴随着多种可能性。 5 | -------------------------------------------------------------------------------- /AndroidandProjects/StarterProjectGenerators.md: -------------------------------------------------------------------------------- 1 | ###初始项目生产器 2 | 3 | 除了通常集成开发环境的新项目向导创建新项目之外,有多个提供线上生成项目的网站: 4 | 5 | * Android Bootstarp 6 | * Android Kickstartr 7 | * 8 | 在这些网站上,你提供了基本的配置数据,例如你的应用包名,然后它们生成完整的初始项目。这些项目比你从集成开发环境得来的显著超前。在加上,你得到了一个更加详尽说明的框架,你可以在它之上搭建你的业务逻辑。但是,理解这些生成器创建的以及如何更改生成的代码需要不少的Android开发经验。 -------------------------------------------------------------------------------- /AudioPlayback/GetYourMediaOn.md: -------------------------------------------------------------------------------- 1 | ###获取你的大众播放媒体媒介 2 | 在Android上,你可以从五个不同的地方拉取媒体剪辑-它们其中的一个会适合你的需求: 3 | 4 | * 你可以把音频剪辑作为原始的资源(你项目中的res/raw)打包,所以它们是和你的应用捆绑在一起的。 5 | 好处是你被赋予了那里的剪辑,坏处是当应用升级的时候它们不会被替换 6 | * 你可以把音频剪辑作为asset(你项目中的asset)并且通过Uri中的file:///android_asset/URLs进行 7 | 引用。优于原始资源的是使用的是Uri参数而不是资源ID。坏处是-仍然存在的asset只在更新时进行替换。 8 | 9 | * 你可以保存媒体到一个应用的本地路径,例如你从网络下载的内容。你的媒体可能存在也可能不存在,并且你的存储空间不是无限的,但是你可以在需要的时候替换媒体。 10 | 11 | * 你可以存储媒体或利用用户存储在SD卡上的。卡上的存储空间会比设备上多,并且你可以在必要的时候替代媒体, 12 | 但是其它的应用也能访问SD卡。 13 | * 在某些情况下,从互利网获取流媒体,传递给本地存储 14 | 15 | 16 | 记住在Android 1.x/2.x的设备上,内部存储是高昂的。这意味着你应该你把小的剪辑放进你的应用(assets/或者res/raw/)并下载较大的剪辑到外部存储。 17 | -------------------------------------------------------------------------------- /AudioPlayback/OtherWaysToMakeNoise.md: -------------------------------------------------------------------------------- 1 | ###其它发出声响的方式 2 | 3 | 虽然MediaPlayer是主要的音频播放选项,特别是对MP3文件来说。构造其它种类的应用时存在其它的替代选项,特别是游戏以及自定义形式的流音频。 4 | 5 | ####SoundPool 6 | 7 | SoundPool类名声在外的原因是加载多个声音的能力,并且以一种按优先顺序列出的方式,所以你的应用可以仅仅要求播放声音而SoundPool处理每个声音的开始,结束,以及播放时的混合。 8 | 9 | 10 | 这用一个样例来说明更有说服力。 11 | 12 | 假定你创建了一个第一人称视角的射击游戏。这个游戏能同时播放多个声音: 13 | 14 | 1.战场上的风声 15 | 2.浪拍打陆地的声音 16 | 3.靴子在沙地上的声音 17 | 4.角色在沙滩上跑动的是气喘嘘嘘的声音 18 | 5.中士在角色后的叫声 19 | 6.瞄准角色机枪的声音以及角色伙伴的声音 20 | 7.提供压制活力的战舰的爆炸声 21 | 22 | 等等。 23 | 24 | 原则上来说,SoundPool可以混合所有这些到单个音频流进行输出。你的游戏可能设置风和浪的声音作为 25 | 恒久不变的背景音,当角色移动的时候触发脚步声,随机地添加吼叫声,在实际游戏的时候绑定枪声。 26 | 27 | 实际上,你的智能手机会缺少处理所有音频而不损耗游戏帧率的CPU能力。所以,为了保持较高的帧率,你要告诉SoundPool同时最多播放两个声音。这就意味着当没有其他事情发生在这个游戏的时候,你会听到风声和浪声,但是在实际发生战斗的时候,这些声音就会被落下-用户可能没有在乎它们-所以这个游戏的速度保持的很好。 28 | 29 | 30 | ####AudioTrack 31 | 32 | Java API最底层用于播放音频的是AudioTrack。它只要有两个职责: 33 | 34 | 1.它的首要职责是支持流音频,流以一种MediaPlayer不能处理的格式进来。虽然MediaPlayer能够处理RTSP,例如,它不能提供SIP。如果你要创建一个SIP客户端(可能是针对一个VOIP或者网络会议应用), 35 | 你会需要把进来的数据流转换为PCM格式,然后把流交给一个AudioTrack实例进行播放。 36 | 37 | 2.它也可以用作“静态的”(对应流)音频字节,你已经预先解码成了PCM格式并且尽可能低延时地进行播放。例如,你可能使用这个作为游戏音(短促的尖声,子弹声,弹开的声音)。不同预解码数据成PCM并缓存结果,使用使用AudioTrack用于播放,你会使用最小的开销,最小化CPU对游戏过程和电池生命的影响。 38 | 39 | ####ToneGenerator 40 | 41 | 如果你想要你的手机听起来很像手机,你可以使用ToneGenerator去播放DTMF音调。换句话说,你可以通过一个常规的手机音模拟对应的按键音。这是被Android拨号器所使用的,例如,当用户使用屏幕上的键盘拨打电话的时候,作为一个音频增强。 42 | 43 | 注意这些会在手机的耳机,话筒或者连接耳机上播放出来。它们没有播放向外的调用流。原则上来说,你可能获取ToneGenerator通过扬声器去播放音调,这个音调足够响从而能被麦克风接起来,但是这不是一个推荐的实践。 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /AudioPlayback/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 理解这章需要你已经读了这本书的核心章回。 4 | -------------------------------------------------------------------------------- /AudioPlayback/README.md: -------------------------------------------------------------------------------- 1 | ##音频播放 2 | 不管是简单的短促尖声还是交响乐又或是匪帮说唱,Android应用通常需要播放音频。Android中一些能够自动播放音频,例如通知。但是以一旦播了,就不能播第二次。 3 | 4 | 幸运的是,Android提供了音频录音重放的支持,并且我们会在这章中分析其中的一些选项。 5 | 6 | 目录: 7 | * [准备工作](/AudioPlayback/Prerequisites.md) 8 | * [获取你的媒介](/AudioPlayback/GetYourMediaOn.md) 9 | * [用于音频的MediaPlayer](/AudioPlayback/MediaPlayerforAudio.md) 10 | * [其它发出声响的方式](/AudioPlayback/OtherWaystoMakeNoise.md) 11 | -------------------------------------------------------------------------------- /AudioRecording/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 理解这章需要你已经阅读过这本书的核心章回。阅读过了音频播放可能也是个好主意。并且在播放本地流的那节中,你会想要攻读下`content provider`,特别是`provider模式`那章。 4 | 5 | -------------------------------------------------------------------------------- /AudioRecording/README.md: -------------------------------------------------------------------------------- 1 | ##音频录制 2 | 3 | 大都数的Android设备有麦克风。在这些设备,很愉快地就能从这些麦克风获取音频输入,不管是本地录制还是 4 | 本地处理(例如语音识别),或者将流输出到互联网(例如,IP语音)。 5 | 6 | 毫不意外,Android在这个领域有着一些特性。同样的,毫不意外,有着很多不同功耗和复杂性的API,来允许你 7 | 捕捉麦克风的输入。在这章中,我们会分析用于录制音频文件的MediaRecorder和用于原始麦克风输入的Audio 8 | Record。 9 | 10 | 目录 11 | * 准备工作 12 | * 通过Intent录制视频 13 | * 录制到文件 14 | * 录制到流 15 | * 请求麦克风 16 | -------------------------------------------------------------------------------- /AudioRecording/RawAudioInput.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/AudioRecording/RawAudioInput.md -------------------------------------------------------------------------------- /AudioRecording/RecordingbyIntent.md: -------------------------------------------------------------------------------- 1 | ###通过Intent进行录制 2 | 3 | 就像使用设备内置的相机拍照时最简单的一样,最简单录制一些音频的方式是使用内置的activity。同时,和使用内置的相机应用,内置的音频录制activity有着一些明显的限制。 4 | 5 | 请求内置的音频录制activity是调用startActivityForResult()用于一个MediaStore.Audio.Media.RECORD_SOUND_ACTION。你可以在Media/SoundRecordIntent样例项目中看到,特别是在MainActivity中: 6 | 7 | package android.app.Activity; 8 | 9 | import android.app.Activity; 10 | import android.content.Intent; 11 | 12 | import android.os.Bundle; 13 | import android.provider.MediaStore; 14 | import android.widget.Toast; 15 | 16 | public class MainActivity extends Activity{ 17 | private static final int REQUEST_ID=1337; 18 | 19 | @Override 20 | public void onCreate(Bundle saveInstaceState){ 21 | Intent i=new Intent(MediaStore.Audio.RECORD_SOUND_ACTION); 22 | 23 | startActivityForReuslt(i,RESULT_ID); 24 | } 25 | 26 | @Override 27 | protected void onActivityResult(int requestCode,int resultCode, 28 | Intent data){ 29 | if(requestCode==REQUEST_ID&&resultCode==RESULT_OK){ 30 | Toast.makeText(this,"Recording finished!",Toast.LENGTH_LONG) 31 | .show(); 32 | } 33 | 34 | finish(); 35 | } 36 | } 37 | 38 | 和这本书中其他少数其它几个样例应用一样,Media/SoundRecordIntent使用的是Theme.NoDisplay activity,回避开了它自己的UI。取而代之的,在onCreate(),我们直接调用了用于MediaStore.Audio.Media.RECORD_SOUND_ACTION。这 39 | 会打开录制的activity: 40 | 41 | 如果用户通过“录制”和停止按钮录制了一些视频,你会在onActivityResult()拿回控制权, 42 | 其中你传入了一个Intent,它的Uri(通过getData())会指向MediaStore中的这个音频录制。 43 | 44 | 但是: 45 | 46 | * 你没有文件存在哪里和文件名的控制权。默认情况下这些文件会被扔在外部存储的根目录。 47 | * 你没有音频录制方式的控制权,例如编解码和比特率。例如,默认情况下文件是录制成AMR格式的。 48 | * ACTION_VIEW 可能不能播放这个音频(至少在一些设备上失败了)。不管是因为编解码还是 49 | 数据在MediaStore中存放的方式,或是Android上默认音频播放器的限制,不是很明确。 50 | 51 | -------------------------------------------------------------------------------- /AudioRecording/RecordingtoStreams.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/AudioRecording/RecordingtoStreams.md -------------------------------------------------------------------------------- /AudioRecording/RequestingtheMicrophone.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/AudioRecording/RequestingtheMicrophone.md -------------------------------------------------------------------------------- /BasicWidgets/ACommandingButton.md: -------------------------------------------------------------------------------- 1 | ###一个命令按钮 2 | -------------------------------------------------------------------------------- /BasicWidgets/AssigningLables.md: -------------------------------------------------------------------------------- 1 | ###给标签赋值 2 | -------------------------------------------------------------------------------- /BasicWidgets/CommonConcepts.md: -------------------------------------------------------------------------------- 1 | ###常见概念 2 | -------------------------------------------------------------------------------- /BasicWidgets/FOGFOOC.md: -------------------------------------------------------------------------------- 1 | ###绿色或其它颜色的域 2 | 3 | -------------------------------------------------------------------------------- /BasicWidgets/FleetingImages.md: -------------------------------------------------------------------------------- 1 | ###稍纵即逝的画面 2 | -------------------------------------------------------------------------------- /BasicWidgets/MoreCommonConcepts.md: -------------------------------------------------------------------------------- 1 | ###更多常见概念 2 | -------------------------------------------------------------------------------- /BasicWidgets/README.md: -------------------------------------------------------------------------------- 1 | ##基础控件 2 | 3 | 每个图形界面界面工具包都有一些基础控件,`fields`,`labels`,`button`等。Android的工具包 4 | 也不例外,并且基础控件会提供一个关于控件如何在Android活动中如何工作的很好的一个介绍。我们 5 | 会在这章中分析其中的一些。 6 | -------------------------------------------------------------------------------- /BasicWidgets/VisittheTrails.md: -------------------------------------------------------------------------------- 1 | ###造访小径 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/C-LBuildviaGradleforAndroid.md: -------------------------------------------------------------------------------- 1 | ###通过Gradle以命令行方式开发Android 2 | 3 | 并且,当然你完全不需要使用集成开发环境。虽然这可能听起来有所不敬,集成开发环境并不是开发的唯一方法。大都数能通过ATD创建的都能通过等同的命令行方式完成,意味着shell和编辑器是你真正所需要的。例如,这本书的作者直到2011年才开始使用集成开发环境。 4 | 5 | Gradle是在集成开发环境外开发Andorid应用的推荐方式。Google发布了一个Gradle插件来教导Gradle开发Android应用。Android Studio 本身使用Gradle来进行构建,就是单独的构建配置。(例如 build.gradle文件)可以同时被集成开发环境和像不间断的集成服务器这样的自动化构建工具使用。 6 | 7 | 紧接着的一章会了解到更多关于Gradle和Android Gradle插件的内容。 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/IDEs...AndThisBook.md: -------------------------------------------------------------------------------- 1 | ###集成开发环境和这本书 2 | 3 | 在接下来学习这本书的过程中,你是欢迎使用Android Studio或Eclipse。如果你想的话你也欢迎使用另一个集成开发环境。你甚至欢迎立即跳过IED而仅仅使用编辑器。 4 | 5 | 这本书主要关注的是展示Andorid功能以及开发这些功能的API。因此,实例代码在任何集成开发环境上都能使用。但是,这边是哪壶会涵盖一些Android Studio和 Eclipse特定的指导,因为它们是今天的主流声音。 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/README.md: -------------------------------------------------------------------------------- 1 | ##选择你的开发工具链 2 | 3 | 在你进一步在Andorid方面努力之前,你需要决定使用什么工具链来开发你的Android应用。 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/WhatWeAreNotCovering.md: -------------------------------------------------------------------------------- 1 | ###我们没有涵盖的内容 2 | 3 | 在开始的时候(2007年),我们有多种创建Android应用的方式。 4 | 5 | 当前,多种方式创建一个Android应用并没有结束。 6 | 7 | 有一些这样的方式,但它们不在这本书的适用范围。 8 | 9 | #####App Inventor 10 | 11 | 你可能听说过叫作App inventor并且疑惑它适用什么地方。 12 | 13 | App Inventor最初是由Google的一个教育组织创建的,意图是教导学生如何像程序结构一样思考(分支、循环等等)并且在没有适用传统java编程或其他语法语言创建有趣的输出(Android 应用)。App Inventor是纯拖放的,包括控件和应用逻辑,后者形成一个逻辑链。 14 | 15 | App Inventor由Google捐献给MIT,最近重新出现在公众的视野。 16 | 17 | 但是,App Inventor是一个封闭的系统-当前,它并不生成你稍后能提高的Java代码。这个限制就是指了App Inventor所能够胜任的,但也让人印象深刻,构成了Andorid SKD功能的一小部分。 18 | 19 | #####应用生成器 20 | 21 | 看起来有无限多个作为在线服务的应用生成器。它们大都数都是创建为特定垂直领域市场提供的应用,例如餐饮应用和杂货应用。产生的应用大都是小册子,比起移动网页没有多多少功能,但是你仍旧需要用户来发现、下载和安装应用。这些应用中何少英提供生成应用的源代码,来允许用户在生成之上进行个性化定制。 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/YetOtherAlternatives.md: -------------------------------------------------------------------------------- 1 | ###还有其它选择 2 | 3 | 其它集成开发环境和ATD有一定等价性,虽然谷歌对其没有什么支持。例如,NetBeans通过NBAndroid插件来进行支持,并且据报道说在过去几年进展很大。Android新手被鼓励不要在使用ApacheAnt开发Andorid应用花费新的时间。 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/androidstudio.md: -------------------------------------------------------------------------------- 1 | ###Android Studio 2 | 3 | 下一代谷歌支持的Android集成开发环境是Android Studio。基于IntelliJIDEA,Android Stdio是新的Google努力的基石为给予Android开发者一流的开发工具。虽然在2014年11月份才出到了1.0,倒是AndroidStudio在多个预览和beta版中已经被使用18个月了。虽然它仍然存在bug,但是无疑已经够稳定来进行应用开发了。 4 | 5 | 下一章包含了一节如何设置Andorid Studio的内容 -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/eclipse.md: -------------------------------------------------------------------------------- 1 | ###Eclipse 2 | 3 | Eclipse 也是一个流行的集成开发环境,特别是对Java开发来说。Eclipse是谷歌最初为Android提供的集成开发环境,通过Android 开发者工具插件,使Eclipse核心感知到Android。ADT插件,本质上,进行一般的Eclipse操作并且对它们进行拓展从而能满足Android项目的要求。 4 | 5 | 注意,尽管如此,Google以及不再维护ADT了。Eclipse基金会启动了"Andmore"项目来尝试继续匀速Eclipse开发Android应用。这本书这次没有包含Andmore项目,Google强烈建议开发者不用使用启动ADT的Eclipse。 6 | 7 | -------------------------------------------------------------------------------- /ChoosingYourDevelopmentToolchain/intelli_idea.md: -------------------------------------------------------------------------------- 1 | ###Intelli IDEA 2 | 3 | 虽然AndroidStudio是基于IntelliJ IDEA,你仍然可以使用最初的IntelliJ IDEA进行Android应用开发。大量Android Studio功能的子集在IDEA Andorid插件里都有。加上,商业IDEA终极版在Andorid开发之外的许多领域是在Android Studio之上的。 -------------------------------------------------------------------------------- /ContentsofAndroidProjects/ProjectsandthisBook.md: -------------------------------------------------------------------------------- 1 | ###项目和这本书 2 | 3 | 这本书中的项目是混合结构的。一些使用新的AndroidStudio结构。其它的使用较老的Eclipse结构。Eclipse形式的项目,虽然可以设置成可以导入到AndroidStudio-它的目录结构仅仅是Eclipse所使用的机构而不是AndroidStudio原本的结构。 4 | 5 | 慢慢地,这本书会把所有的项目转成AndroidStudio结构的。这个进程会在2016的某个时间完成。 -------------------------------------------------------------------------------- /ContentsofAndroidProjects/README.md: -------------------------------------------------------------------------------- 1 | ##Android项目内容 2 | 3 | Android构建系统为是为你的Android项目构建成一个特定的目录树结构而组织而成的,很像其它的Java项目。细节是,虽然对Android来说一定程度上是独一无二的,Android构建工具做了一些额外的事情为真正运行在设备或模拟器上的应用做准备。 4 | 5 | 使事情变的更复杂是默认的结构的不同是当前工具(例如,AndroidStudio)和历史工具(例如,带有ADT插件的Eclipse)的不同之处。 6 | 7 | 这里是一个项目结构的快速入门,来帮助你全面地了解它,尤其是这本书参考的样例代码。 8 | 9 | -------------------------------------------------------------------------------- /ContentsofAndroidProjects/TheContentsofanAndroidStudioProject.md: -------------------------------------------------------------------------------- 1 | ###AndroidStudio项目的内容 2 | 一个AndroidStudio项目是明显比一个Eclipse项目要复杂的。这个复杂性是为了当你成为一个Android开发专家的时候给你更多力量。 3 | 4 | 尽管就短期而言,它有点让人困惑。 5 | 6 | ####根目录 7 | 在你项目根目录下,最重要的项是app/目录,它是你应用代码所在的地方。我们会在下一节看看它。 8 | 9 | 除了app/目录,在根目录下其它值得注意的文件包括: 10 | 11 | * build.gradle,如上所述是你项目构建指令的一部分。 12 | * 多种其它的Gradle相关文件(settings.gradle,gradle.properties等等) 13 | * local.properties,指示Android SDK工具的位置 14 | * .imp文件,在里面有着一些附加关于你项目的原数据 15 | ####App目录 16 | app目录以及它的内容,是你作为一个开发者所花费大部分时间的地方。你很少需要操作根目录中的文件。 17 | 18 | 在app目录中最重要的是src的目录,它是你项目源集的根,它会在下一节中描述。 19 | 20 | 除了src目录,在app/中有一些其它需要注意的项 21 | 22 | * 一个build/目录,它会包含构建你应用的输出,包含你的APK文件 23 | * 一个build.gradle文件,是你大都数你的项目特有的Gradle配置会在的地方,来教导AndroidStudio如何构建你的应用。 24 | * 一个app.imp文件,包含了更多的AndroidStudio原数据 25 | ####源集 26 | 源集是你项目组织“源”的地方。这里,“源”不仅仅是编程语言代码(例如,java),还有其它构建的输入类型,例如你的资源。 27 | 28 | 源集中你将会花费大部分你的时间的是main/。你会有一个叫作androidTest的存根源集,它是用来创建unit测试的,会在之后的内容里涵盖到。 29 | 30 | 在源集中,你可以有: 31 | 32 | * Java代码,在一个java/目录中 33 | * 资源,在一个res/目录中 34 | * 资产,在一个assets目录中,代表其它你想要打包进应用安装到设备的静态文件。 35 | * 你的AndroidManifest.xml文件 36 | -------------------------------------------------------------------------------- /ContentsofAndroidProjects/TheContentsofanEclipseProject.md: -------------------------------------------------------------------------------- 1 | ###Eclipse项目的内容 2 | 当你在Eclipse项目中创建项目的时候,你会在项目的根目录获得一些项,包括: 3 | 4 | 1.如上所述的AndroidManifest.xml 5 | 6 | 2.bin/,包含应用一旦编译之后的东西(注意:这个目录会在你首次构建你的应用时生成) 7 | 8 | 3.res/,包含了如上所述的你的资源 9 | 10 | 4.src/,包含了应用的java源代码 11 | 12 | 除了以上的文件和目录,你可能在Android项目中发现以下的任何一个: 13 | 14 | 1.assets/,包含了其它你想要打包进安装在设备的应用中的 15 | 16 | 2.gen/,存放Android的构建工具生成的源代码 17 | 18 | 3.libs/,存放你应用需要的人和第三方java的JAR包 19 | 20 | 4.*properties,包含了你构建的配置数据 21 | 22 | 5.proguard.cfg或proguard-project.txt,用来集成ProGuard来混淆你的Android代码 23 | 24 | 6.隐藏的Eclipse项目文件(例如.classpath) 25 | -------------------------------------------------------------------------------- /ContentsofAndroidProjects/WhatYouGet,InGeneral.md: -------------------------------------------------------------------------------- 1 | ###一般来说,你得到的东西 2 | 项目的文件具体细节取决你选择的集成开发环境。但是,不管你是使用AndroidStudio还是 3 | Eclipse,是有许多共同元素的。 4 | 5 | 一般来说,你得到的东西 6 | 项目的文件具体细节取决你选择的集成开发环境。但是,不管你是使用AndroidStudio还是Eclipse,是有许多共同元素的。 7 | 8 | ####Manifest 9 | AndroidManifest.xml 是一个描述应用创建以及什么组件被应用供应。你可以把它当作是应用的内容列表,跟书的目录列出出现在书中的多个部分,章节以及附录差不多。 10 | 11 | 我们会在下一章中更为密切地检查manifest。 12 | 13 | ####Java 14 | 当你创建项目的时候,你为应用主活动提供了完全合格的类名(例如.com.commonsware.android.SomeDemo)。然后你会发现你的项目的Java源代码树就报名目录已经摆放好了,外加一个存根活动子类表示你的主活动。(例如,src/com/commonsware/android/SomeDemoActivity.java)。为了实现你的应用,你是欢迎对这个文件就行修改并添加需要的Java类的。并且我们会在这本书的进程中无数次地对其进行描述。 15 | 16 | 其它地方-在你通常不会使用的目录中-Android构建工具也会在你每次构建你的应用的时候代码生成一些源代码。代码生成类中其一就有R.java,它对从我们的java代码控制我们的用户界面是很重要的。并且我们将会在真正开始构建应用的时候看到很多对这个R类的引用。 17 | 18 | ####资源 19 | 你会发现你的项目有一个res/目录树。这其中包含了“资源”-随应用仪器打包的静态文件,以原始的或者预处理的形式。一些你会发现或在res下创建的子目录包括: 20 | 21 | 1.res/drawable/ 给图片(PNG,JPEG,等等) 22 | 23 | 2.res/layout/ 给基于XML的布局说明书 24 | 25 | 3.res/menu/ 给基于XML的菜单说明书 26 | 27 | 4.res/raw 给通用的文件(例如一个音频片段,用户信息的CSV文件) 28 | 29 | 5.res/values 给字符串,尺寸等等 30 | 31 | 6.res/xml 其它你想要装的通用XML文件 32 | 33 | 一些子目录可能有后缀,像res/drawable-hdpi/。这指示这个资源目录只应该在特定环境下使用-在此例中,图片资源应该只在高密度的屏幕上使用。 34 | 35 | 在这本书稍后的内容,我们会涵盖所有这些内容,并更加详细。 36 | 37 | ####构建指令 38 | 集成开发环境需要知道如何获取这些东西并得到一个Andorid APK文件。一些基于集成开发环境是如何写的以及被知晓了。但是一些细节是你可能需要时不时地去配置的,所以这些细节存储在你会编辑的文件中,从你的集成开发环境通过一种或另一种方式。 39 | 40 | 在AndroidStudio中,大都数这些知识是保存在一个或多个叫做build.gradle的文件中的。这些是Gradle的构建引擎,是AndroidStudio用了构建APK和其它Android输出用的。 41 | 42 | 在Eclipse中,这些知识分散在多个文件中,一些是你手动编辑的(例如.project.properties)。一些是只能通过Eclipse修改的(例如.classpath)。 43 | 44 | 45 | -------------------------------------------------------------------------------- /ContentsofAndroidProjects/WhatYouGetOutOfIt.md: -------------------------------------------------------------------------------- 1 | ###你从它得到了什么 2 | 作为你运行你的应用在设备或模拟器上的一部分,集成开发环境会生成一个APK文件。你会发现这个: 3 | 4 | 在你的AndroidStudio项目的build/outputs/apk目录中,如果项目没有单元(例如没有app目录),或者 5 | 在你的单元的build/outputs/apk目录中,(例如,传统AndroidStudio项目的app/build/outputs/apk),或者 6 | 在你的Eclipse的bin目录 7 | APK文件是包含你编译Java类的zip压缩包,你的资源的编译版本(resource.arsc),任一的未编译的资源(例如你放进res/raw/文件夹的),以及AndroidManifest.xml文件。如果你构建了调试版本的应用-默认的。对于一个叫作yourapp的应用来说,你会得到你的app-debug.apk作为你的APK。 -------------------------------------------------------------------------------- /CustomDrawables/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 理解这章需要你已经读过核心章节,特别是[基础资源](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/SomeWordsAboutResource)和[基础控件](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/BasicWidgets)这两章。 4 | 5 | 已经读过[动画]()和[旧式动画]()将会大用用处。 6 | 7 | -------------------------------------------------------------------------------- /CustomDrawables/README.md: -------------------------------------------------------------------------------- 1 | ## 自定义`Drawables` 2 | 3 | 很多时候,我们的图片可以仅仅是一些PNG或JPEG文件,不同密度资源文件下各不相同。 4 | 5 | 尽管如此,有时候我们需要的会更多。 6 | 7 | 除了支持标准的PNG和JPEG文件之外,Android有很多自定义drawable资源格式-大部分是写在 8 | XML中用来处理特定的情形。 9 | 10 | 例如。你想要自定义一个按钮的“背景",但是一个按钮真的有很多针对不同情形的不同背景图片(normal, 11 | pressed,focused,disabled,等等.)。Android有着特定类型的drawable资源可以集合其它的drawable 12 | 资源,指示不同情形下该用什么资源(例如,normal按钮用x,disabled按钮用y)。 13 | 14 | 在本章中,我们会探索这些非传统类型的drawables并且告诉你如何在你的应用中使用。 15 | 16 | -------------------------------------------------------------------------------- /DealingWithThreads/AlternativestoAsyncTask.md: -------------------------------------------------------------------------------- 1 | ###`AsyncTask`的替代方案 2 | 3 | android中存在着不使用`AsyncTask`处理后台线程的其它方法: 4 | 5 | * 你可以使用一个Handler,它有着一个会在主应用线程,处理从后台线程发送而来的消息对象 6 | 的handleMessage()方法。 7 | 8 | * 你可以提供一个在主应用线程执行的Runnable来在任一视图上进行post(),或在Activity上 9 | 调用runOnUiThread()。 10 | 11 | * 你可以提供一个Runnable,外加毫秒级的延迟时间,在任一视图上进行postDelayed(), 12 | 在至少几毫米过去之后再在主应用线程上运行Runnable。 13 | 14 | 这些当中,Runnable选项是最易使用的。 15 | 16 | 这些也能用来让主应用线程来推迟工作,稍后在主应用线程上完成。例如,你可以使用 17 | postDelayed()设置一个轻量级不需要额外的线程开销的轮询循环,例如 18 | 由Timer和TimeTask创建的。要了解这是怎么工作的,让我们瞧一瞧[Threads/postDelayed](https://github.com/commonsguy/cw-omnibus/tree/master/Threads/PostDelayed) 19 | 这个样例项目。 20 | 21 | 这个项目包含了单个叫做postDelayedDemo的activity: 22 | 23 | package com.commonsware.android.post; 24 | 25 | import android.app.Activity; 26 | import android.os.Bundle; 27 | import android.view.View; 28 | import android.widget.Toast; 29 | 30 | public class PostDelayedDemo extends Activity implements Runnable { 31 | private static final int PERIOD=5000; 32 | private View root=null; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.main); 38 | root=findViewById(android.R.id.content); 39 | } 40 | 41 | @Override 42 | public void onResume() { 43 | super.onResume(); 44 | 45 | run(); 46 | } 47 | 48 | @Override 49 | public void onPause() { 50 | root.removeCallbacks(this); 51 | 52 | super.onPause(); 53 | } 54 | 55 | @Override 56 | public void run() { 57 | Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT) 58 | .show(); 59 | root.postDelayed(this, PERIOD); 60 | } 61 | } 62 | 63 | 我们想要每隔5秒钟显示一个Toast。为了这么做,在onCreate()中,我们通过findViewById()获取了 64 | 我们的被称为android.R.id.content处理单个activity的UI的容器。然后,在onResume()中, 65 | 我们调用了我们activity的run()方法,它展示了Toast然后调用了postDelayed()来进行自我调度(以Runnable的实现的方式)。 66 | 当我们的activity位于前台的时候,作为结果Toast每PEROID毫秒之后都会出现。 67 | 一旦有别的东西来到的前台,例如用户按下了返回键——我们的onPause()方法 68 | 被调用了,其中我们调用了removeCallbacks()来撤销postDelayed()的调用。 69 | -------------------------------------------------------------------------------- /DealingWithThreads/AndNow,TheCaveats.md: -------------------------------------------------------------------------------- 1 | ###警告 2 | 3 | 后台线程,特别是使用`AsyncTask`及其同类的时候,不总是欢声笑语的。后台线程不仅增加了复杂性, 4 | 就可用内存,CPU和电池寿命而言它们有着真实的开销。 5 | 6 | 为此,你需要为你的后台线程考虑很多的情形,包括: 7 | 8 | 1.用户和你的activity的UI交互的时候后台线程在执行的可能性。如果后台线程 9 | 所做的工作是由用户输入修改或取消的,你会需要就这个问题和后台线程进行通讯。 10 | Android在`java.util.concurrent`包中包含了许多类,这些类会帮助你与你的后台线程进行安全通讯。 11 | 12 | 2.当工作仍在进行而进程被终止了的可能性。这就是为什么在许多情形中,不是使用一个`AsyncTask`或 13 | 光秃秃的一个线程,你会以使用一个`Service`收尾,例如一个`IntentService`。这会在 14 | [这本书稍后内容中](/ServicesandtheCommandPattern/README.md)进行详细探讨。 15 | 16 | 3.如果你吃掉了大量的CPU时间和电池寿命而没有进行任何回收的话,你的用户可能会因此而恼怒的可能性。 17 | 策略上,这意味着使用进度条或其它方式让用户知道有事情正在发生。战略上,这意味着你在做你的事情的时候 18 | 需要是高效的——后台线程不是缓慢或无意义代码的万能药。 19 | 20 | 4.在后台线程执行过程中遇到错误的可能性。例如,如果你正在从互联网收集信息,设备可能会丢失连接。 21 | 通过一个通知警告用户这个问题并关闭后台线程可能是你最好的选择。 22 | -------------------------------------------------------------------------------- /DealingWithThreads/GettingtotheBackground.md: -------------------------------------------------------------------------------- 1 | ###来到后台 2 | 3 | 因此,你需要把耗时的工作移到后台线程中去,但是这些线程需要做一些事情才能安排使用主应用线程做 4 | 更新UI的操作。 5 | 6 | Android中有许多帮助做这件事的工具。 7 | 8 | 一些是为解决主功能区问题的高层次框架。其中一个例子就是从数据库获取信息的Loader框架,并且我们会 9 | 在[稍后一章](/TheLoaderFramework/README.md)中来分析这个框架。 10 | 11 | 有时候,存在内置进其它Android操作的异步选项。例如,我们[稍后一章](/UsingPreferences/README.md) 12 | 会讨论的`SharedPreferences`,我们会看到我们能够以异步或同步的方式进行持久化。 13 | 14 | 也有一把为解决这个问题的底层解决方案,你可以在其上面实现你自定义的业务逻辑。 15 | -------------------------------------------------------------------------------- /DealingWithThreads/README.md: -------------------------------------------------------------------------------- 1 | ##线程的处理 2 | 3 | 用户喜欢快速的应用。用户不喜欢感觉起来很慢的应用。 4 | 5 | 使用Android内置的标准线程功能,会有助于你应用的响应速度。这章会过一遍Android中涉及到与 6 | 线程管理相关的问题,并且会带你熟悉一些用于保持用户界面快速响应的选项。 7 | 8 | 目录: 9 | 10 | * [主应用线程](/DealingWithThreads/TheMainApplicationThread.md) 11 | * [来到后台](/DealingWithThreads/GettingtotheBackground.md) 12 | * [感受异步](/DealingWithThreads/AsyncingFeeling.md) 13 | * [`AsyncTask`的替代方案](/DealingWithThreads/AlternativestoAsyncTask.md) 14 | * [警告](/DealingWithThreads/AndNow,TheCaveats.md) 15 | * [事件总线](/DealingWithThreads/EventBuses.md) 16 | * [造访小径](/DealingWithThreads/VisittheTrails!.md) 17 | -------------------------------------------------------------------------------- /DealingWithThreads/TheMainApplicationThread.md: -------------------------------------------------------------------------------- 1 | ###主应用线程 2 | 3 | 当你在`TextView`上调用`setText()`的时候,你可能认为屏幕是马上被你所提供的文本更新的。 4 | 5 | 那你就弄错了。 6 | 7 | 而实际上,所有基于控件UI的修改都会经由一个消息队列。对`setText()`的调用并没有更新屏幕-它们 8 | 仅仅是放置了一个消息在一个队列上,告诉操作系统要更新屏幕。操作系统将这些消息从这个队列中弹出, 9 | 并且做了消息所要求的事情。 10 | 11 | 这个队列是用一个线程进行处理的,又称“主应用线程”或”UI线程"。只要这个线程能保持处理消息的状态, 12 | 屏幕就会被更新,用户输入等操作就会被处理。 13 | 14 | 但是,主应用线程也被你activity中几乎所有的回调使用。你的onCreate(),onClick(),onListItemClick(), 15 | 以及相类似的方法都是在主应用线程中被调用的。当你的代码执行在这些方法中的时候,Android并没有处理 16 | 位于队列中的消息,并且所以屏幕没有更新,用户输入等操作没有被处理。 17 | 18 | 这当然是糟糕的。很糟糕,如果你在主应用线程上花费了超过几秒的时间来做一些工作话, 19 | Android就可能会显示出令人生畏的“应用无应答”对话框,并且你的activity可能会被杀死。 20 | 21 | 尽管如此,现如今更令人担忧的是`jank`。 22 | 23 | Android中所使用的"Jank"指的是缓慢的UI更新,尤其是有动画的时候。例如,你可能已经遇到过一些 24 | 这样的应用,当你滚动应用中的`ListView`的时候,`ListView`并没有很平滑的滚动。而是,滚动地很不平稳, 25 | 交织着一段快速移动,移动过程中是没有动画的。大都数情况下,这是由于应用的作者在主应用线程做了 26 | 太多工作而造成的。 27 | 28 | Android 4.1 中引入了“Project Butter”,其中建立了一个“在应用主线程做太多工作”的基准线。 29 | 如果每帧花费了超过16ms的时间,我们就会掉帧,掉帧就是`jank`的源头。因为我们可能在一帧中被调用 30 | 很多次,我们的每个调用需要是十分便宜的,最好是1ms以下。我们会在这本书[随后内容](/FindingandEliminatingJank/README.md) 31 | 中看到更多有关`jank`的内容,但是现在要理解的是主线程上代码执行过程中的任何明显的延迟对用户来 32 | 说都是可见的。 33 | 34 | 因此,你要确保你所有在主应用线程的工作都是能很快就完成的。这就意味着任何缓慢的都应该在一个 35 | 后台线程中去完成而不要捆绑到主应用线程上去。这包含像以下的东西: 36 | 37 | 1. 网络访问,例如发送数据到一个Web服务或者下载一张图片 38 | 39 | 2. 大量的文件操作,因为有时闪存会是非常慢的 40 | 41 | 3. 任何形式的复杂计算 42 | 43 | 幸运的是,Android支持线程使用来自Java的标准线程类,外加所有你所能预料的装箱和控制结构,例如 44 | java.util.concurrent类包。 45 | 46 | 但是,存在一个大的限制:你不能从后台线程修改UI。你只能从主应用线程修改UI。 47 | 如果你从一个后台线程在`TextView`上调用`setText()`,你的应用会闪退,抛出一个指示你在从非UI线程修改UI的异常。 48 | 49 | 这是一个痛。 50 | -------------------------------------------------------------------------------- /DealingWithThreads/VisittheTrails!.md: -------------------------------------------------------------------------------- 1 | ###造访小径 2 | 3 | 我们在[稍后一章中](/FindingandEliminatingJank/README.md)会涵盖到更多关于jank的内容, 4 | 以及如何检测和诊断它。 5 | 6 | 在`greenrobot EventBus`实现上还有更多特性。我们会在之后的[事件总线的替代方案]() 7 | 这一章中看看其中一些特性,外加其他事件总线的实现。 8 | -------------------------------------------------------------------------------- /EventBusAlternatives/README.md: -------------------------------------------------------------------------------- 1 | ###事件总线替代方案 2 | -------------------------------------------------------------------------------- /FindingandEliminatingJank/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/FindingandEliminatingJank/README.md -------------------------------------------------------------------------------- /FoucusOnNDK/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 理解这章的内容需要你已经读过核心章回以及理解Android应用是如何设置和操作的。读下 3 | 这个小径的绪论也会是个好主意。 4 | 5 | 这章也假定你了解C/C++编程。 6 | -------------------------------------------------------------------------------- /FoucusOnNDK/README.md: -------------------------------------------------------------------------------- 1 | ##关注NDK 2 | 当Android首发的时候,许多开发者想要在它上面运行C/C++代码。除了发布一个二进制可执行文件并 3 | 通过一个派生进程运行它之外,几乎没有对于C/C++代码的支持。这个虽然能用,但是却有点笨重,并且 4 | 基于进程的接口你的C/C++代码如何与基于Java的UI进行利落的交互。最重要的,二进制可执行文件的使用 5 | 的支持并不是很好。 6 | 7 | 在2009年6月,Android核心小组发布了`Native Development Kit(NDK)`。这允许开发者以一种被 8 | 支持的方式为Android应用编写C/C++,通过`Java Native Interface(JNI)`把类库链接到基于 9 | Java的宿主应用上。这给Android开发提供了大量的机会,并且书的这部分内容会分析你该如何利用好NDK 10 | 去利用这些机会。 11 | 12 | 这章会分析如何设置NDK并把它应用到你的项目上。它并没有尝试覆盖所有可能的NDK使用-尤其是使用了像 13 | OpenGL和OpenSL许多框架的游戏应用,是超出本书的范围的。 14 | 15 | 目录: 16 | 17 | * [准备工作](/FoucusOnNDK/Prerequisites.md) 18 | * NDK的职责 19 | * NDK安装和项目设置 20 | * 编写你的MakeFile 21 | * 构建你的类库 22 | * 通过JNI使用你的类库 23 | * 构建并部署你的项目 24 | * `Gradle`和NDK 25 | -------------------------------------------------------------------------------- /FoucusOnNDK/TheRoleoftheNDK.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/FoucusOnNDK/TheRoleoftheNDK.md -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/AccessingAndroidTools.md: -------------------------------------------------------------------------------- 1 | ###使用Android工具 2 | 不是所有与Android有关的都是直接在AndroidStudio中的。在一些例子中,工具需要被使多个AndroidStudio用户、Eclipse用户以及没提到的用户所共享。在某些情况下,虽然长远来说可能会把这些工具的功能直接整合进AndroidStudio,但是并没有完成日期。 3 | 4 | 这有一些你可以通过Tools>Android主菜单选项获取的值得注意的Android相关的工具。 5 | 6 | ####SDK和AVD管理器 7 | 正如我们在教程#1中所看到的,SDK管理器时Android下载AndroidSDK部件的工具,包括: 8 | 9 | "SDK平台"版本,允许我们在一个特定的API等级上编译 10 | ARM和(有时候)x86模拟器镜像 11 | 文档 12 | 更新核心构造工具 13 | 等等 14 | 你可以通过AndroidStudio主菜单上的Tools>Android>SDK Manager启动SDK管理器,或者点击“droid in a box”的工具栏按钮。 15 | 16 | AVD管理器时用来创建模拟基于API等级,屏幕尺寸和其它因素的特定Android环境的模拟器的工具/ 17 | 18 | 你可以通过AndoridStudio主菜单上的Tools>Android>AVD管理器启动应用,或通过点击“droid and a screen”工具栏按钮。 19 | 20 | ####Android设备检测仪 21 | 22 | 在这本书的别处,你会看到与Dalivik Debug Monitor Server(DDMS)相关的工具参考,例如使用使用它帮助审查你的所运行应用的内存和线程问题。你也会看到像Hierarchy view的工具参考,在你用代码作出很多改变之后,用来在运行时了解你的用户界面。 23 | 24 | 在Eclipse中,DDMS和Hierarchy View是视角,通过ADT插件的方式添加。 25 | 26 | 对于不使用Eclipse的人来说,包括AndroidStudio用户,DDMSh和Hierarchy View 是通过Android Studio设备检测仪这个独立工具获取的。AndroidStudio用户可以通过主菜单上的Tools>Android>Android Device Monitor启动检测仪。 27 | 28 | 首先是一个启动界面: 29 | 30 | 然后就是检测仪本身: 31 | 32 | 如果你在网上阅读了关于从DDMS或Hierarchy的事情,例如在博客或Stackoverflow的答案区,大都数这些功能都应该能通过Android设备检测仪得到。 -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/AndroidStudioandReleaseChannels.md: -------------------------------------------------------------------------------- 1 | ###AndroidStudio和发行渠道 2 | 当你首次安装AndroidStudio的时候,你的安装会被设置成从稳定发行渠道获取更新。这里,“发行渠道”是特定的可能更新集合。稳定意味着你获取的是充分做好生产准备的更新。AndroidStudio会在启动的时候检查更新,并且你可以通过住菜单手动检查更新(例如Help>Check for Update....在Windows和Linux). 3 | 4 | 如果有可用的更新,在你面前会展现一个关于更新细节的对话框。 5 | 6 | 选择“Release Notes”会带来一个关于新的发布的发布记录的网页。点击“Update and Restart”做了按钮名称所提议的事情,它下载了更新并重启了集成开发环境,同时应用了更新。 7 | 8 | 点击对话框中“Updates”的超链接会带来另一个对话框,允许你选择一个你想要订阅的发布版本: 9 | 10 | 你有四个渠道可以选择: 11 | 12 | * 稳定,对大都数开发者是适用的 13 | * Beta,比稳定版略为领先更新 14 | * Dev,比beta渠道还早 15 | * Canary,更新早很多(并且名字寓意着煤矿中的钻石,指示你是在这帮助调试集成开发环境的。) 16 | 17 | -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/NavigatingTheProjectExplorer.md: -------------------------------------------------------------------------------- 1 | ###浏览项目资源管理器 2 | 在主要编辑区域-你修改你java源代码、资源等等的地方之后,Android Studio中区片中你将要话费最多时间的是项目资源管理器,通常是在集成开发环境窗口的左侧: 3 | 4 | 理论上,Android项目视图设计成为了简化Android项目文件的工作。实际上,它确实做到了,但是只是对一些高级开发者。整体上来说,它使Android初学者觉得集成开发环境更复杂了,因为它对于看清位置和事物相关性使相当困难的。 5 | 6 | 我们会在这本书较后的内容中返回到Android项目视图并解释与资源和gradle的资源集相关的好处。 7 | 8 | 但是,对这本书的绝大部份内容,最重要的,对这个教程,我们会使用传统的项目视图。 9 | 10 | ####传统项目视图 11 | 为了切换到传统的项目视图,点击项目管理器树上的下拉按钮,并选择Project: 12 | 13 | 这会改变展示所有文件的内容树,在它们相关的目录中: 14 | 15 | 这个项目视图跟其他集成开发环境的是差不多的,允许你找到你Android项目中的所有部分。在下一章中,我们会探索这些部分是什么,以及它们的文件在我们的项目中是如何组织的。 16 | 17 | ####资源管理器中的上下文菜单 18 | 在项目管理器中的一个目录或文件上右击会给你一个有多个选项的上下文菜单。它们中的一些事任何文件管理器代表性的,例如“cut”,"copy",和“paste”选项。它们中的一些会对应于IntelliJ IDEA如何管理应用开发,例如“Refactor”子菜单,在这你可以重命名或移动文件。还有其它AndroidStudio特定的,例如掉哦那个向导创建特定类型的Android组建或其它Java类的能力。 19 | 20 | -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/README.md: -------------------------------------------------------------------------------- 1 | ##熟悉AndroidStudio 2 | Eclipse已经存在很长的一段时间了并且被证明是一个很流行的集成开发环境。作为结果,有相当多关于它的材料,从书籍博客到Stack Overflow上的问题和官方项目文档。 3 | 4 | Android Studio跟它的父亲,IntelliJIDEA有很多共同功能。但是,IDEA本身没有取得像Eclipse这样等级的受欢迎程度,即使它作为许多开发商的选择已经有一段时日了。并且AndroidStudio的对IDEA的更改大部分是没有文档化的。 5 | 6 | 因此,这章将作为AndroidStudio集成开发环境的一个快速教程,来帮助你得到解决。其他Android中Android特有的功能会在章节接下来的内容中进行探索。 -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/RunningProjects.md: -------------------------------------------------------------------------------- 1 | ###运行项目 2 | 正如教程#2中提到的,只要按下运行工具栏按钮(通常是朝向右边的绿色三角形)。在你面前就会呈现一个让你选在哪运行应用的对话框,在某个已存在的设备或模拟器,或在某一个新启动的模拟器: 3 | 4 | 如果你没有一个正在运行的模拟器,从对话框底部的下拉菜单中选一个。不管你是启动一个新的模拟器实例,重用一个已经存在的,或者请求运行在已连接的Android设备上,你的应用都会出现在上面。 5 | 6 | -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/ViewingOutput.md: -------------------------------------------------------------------------------- 1 | ###浏览输出 2 | 在你的应用上,AndroidStudio会生成其它种类的诊断输出,以已经发生的事情的控制台脚本的形式。 这些输出中对你可能最重要的可能是gradle终端和LogCat. 3 | 4 | ####Gradle终端 5 | 默认时,Gradle终端项时位于AndroidStudio窗口右下脚的。点击它会打开一个展示尝试构建你应用的输出的面板: 6 | 7 | 这可能时不时地自动出现,如果侦测到特定的构建问题,然后当你需要的时候你总是能去检查查。 8 | 9 | 再次点击Gradle终端项就把窗口给关闭了。 10 | 11 | ####LogCat 12 | 在运行时出现的消息-包括所有重要的由你代码中bug触发的Java栈足迹-在LogCat中都是可见的。"Android"项位于AndroidStudio窗口的左下角,当轻拍的时候就回显现。 13 | 14 | LogCat会在这本书稍后内容中更加详细地进行解释。 15 | 16 | -------------------------------------------------------------------------------- /GettingAroundAndroidStudio/VisittheTrails.md: -------------------------------------------------------------------------------- 1 | ###造访小径 2 | 3 | Android Studio 的项目结构对话框和翻译编辑器会涵盖在[之后内容中]()。 -------------------------------------------------------------------------------- /GradleandDependencies/APropertyofTransitive.md: -------------------------------------------------------------------------------- 1 | ###一个传递依赖的特性 2 | 当指定依赖的时候要小心你的依赖的依赖来自哪里。简短检查这些依赖的配置文件之后(例如,它们的 3 | Maven POM文件),你没有好的办法知道你的依赖的依赖是什么,更不用说它们来自哪里。 4 | 5 | 尽管如此,根据Gradleware: 6 | 7 | 只有为项目声明仓库,它的配置甚至传递依赖的会被包含在内。 8 | 9 | 所以,例如,假定应用A依赖于库B,B又转而依赖库C。库B是你团队自己内部的Maven仓库,而 10 | 库C来自于MavenCentral为了能够让Gradle能同时包含两个类库,应用需要把你自己的Maven仓库和 11 | Maven Central 定义在依赖闭包中。 12 | -------------------------------------------------------------------------------- /GradleandDependencies/APropertyofTransitiveDependencies.md: -------------------------------------------------------------------------------- 1 | ###一个传递依赖的特性 2 | 当指定依赖的时候要小心你的依赖的依赖是来自哪里。对于这些依赖的配置文件(例如,Maven POM文件)进行短暂检查之后。 3 | ,你没有办法知道你的依赖的依赖是什么,更不用说它们从哪里来。 4 | 5 | 尽管如此,依据Gradelware: 6 | -------------------------------------------------------------------------------- /GradleandDependencies/ATaleofTwoDenpendenciesClosures.md: -------------------------------------------------------------------------------- 1 | ###两个依赖闭包的故事 2 | 3 | 经典Android项目中的一个build.gradle文件或者build.gradle文件对-将有两个依赖闭包。 4 | 5 | 一个会在buildscript闭包中,并且这个依赖集是构建过程本身的依赖。在这里,我们会列出例如Android 6 | 构建工具之类的依赖,这些依赖定义了我们所能配置android选项。 7 | 8 | 依赖闭包是伴随着构建脚本的,并且android为项目列出了被这个特定build.gradle所构建的依赖。 9 | 10 | 换句话说,构建脚本依赖是工具依赖。与此同时,常规的依赖来源是第三方代码。 11 | -------------------------------------------------------------------------------- /GradleandDependencies/CreatingAndroidJARsfromGradle.md: -------------------------------------------------------------------------------- 1 | ###从Gradle创建Jar包 2 | 3 | Gralde被用于Java开发已经有一段时间了,并且标准的用于Gradle的java插件知道如何创建JAR文件。 4 | 5 | 但是,我们使用的不是java插件。作为替代,我们使用的是android或android-library插件。在 6 | 后一种情况下,你可能提出它应该支持创建Jar包的任务,因为类库并没有使用资源等东西。不幸的是, 7 | 它没有,至少现在没有。因此,android或android类库项目中没有创建jar包的任务。 8 | 9 | 因为这些情形很常见,Jake Wharton就出来救场了。 10 | 11 | 在StackOverflow上Jake发布了一个提供应急的Gradle代码片段添加JAR包到android类库项目的回答。 12 | 13 | android.libraryVariants.all{ variant-> 14 | def name = variant.buildType.name 15 | if(name.equals(com.android.builder.core.BuilderConstants.DEBUG)){ 16 | return; 17 | } 18 | def task=project.tasks.create "jar${name.capitalize()}",Jar 19 | task.dependsOn variant.javaCompile 20 | task.from variant.javaCompile.destinationDir 21 | } 22 | 23 | Groovy中的Gradle DSL主要是包含了构建数据结构。因为我们所有的构建变量会存在于android.libraryVariants 24 | 中。Jake的代码片段遍历了这些,筛掉那些针对debug构建的,并且会自动定义一个新的任务。新的任务会被命名 25 | 成jar...,...是构建类型的名称。他的代码片段然后会配置任务创建一个JAR文件,在代码编译之后,把结构 26 | 放在Java编译的目标路径。 27 | 28 | 把这个片段放在你的build.gradle文件的底部的最终结构是会添加一个像jarRelease的任务。注意, 29 | jarRelease任务在你运行gradle tasks的时候没有出现,而是在你运行gradle tasks -all 30 | 获取完整列表的时候才会出现。 31 | 32 | 这没有创建一个完整的Jar包的artifact,所以如果你的计划是提交这个JAR到一个artifact仓库, 33 | 你会要做些额外的工作。但是创建手动发布的JAR包来说,它应该能胜任。 34 | -------------------------------------------------------------------------------- /GradleandDependencies/DenpendingUponanAndroidLibraryProject.md: -------------------------------------------------------------------------------- 1 | ###依赖于一个Android类库项目 2 | Android类库项目已经成为了项目之间共享代码的流行方式,因为它们除了Java代码之外还有资源。 3 | 对于项目之间的代码重用,一些开发者会完全在内部使用Android类库项目。一些开发者会依赖于 4 | 第三方类库项目,例如控件类库或者Google的action bar模式的appcompat-v7向后兼容。一些 5 | 开发者会发布它们自己的类库被第三方使用。 6 | 7 | 其核心是,Android类库项目当使用Gradle构建的时候对比使用Ant或者Eclipse构建的时候,并没有 8 | 改变很多。但是,你告诉Android这个项目是一个类库项目,以及你使用类库项目的方式,已经改变了很多。 9 | 10 | ####创建一个类库项目 11 | 就如在Android类库项目那章多提及的,常规Android项目和Android类库项目的主要区别是,就 12 | Gradle配置而言,是你所使用的插件。常规的应用项目会使用com.android.application插件, 13 | 而Android类库项目会使用com.android.library插件: 14 | 15 | buildscript{ 16 | repositories{ 17 | mavenCentral() 18 | } 19 | denpendencies{ 20 | classpath 'com.android.tools.build:gradle:2.1.0' 21 | } 22 | apply plugin:'com.android.library' 23 | 24 | android{ 25 | compileSdkVersion 19 26 | buildToolsVersion "21.1.2" 27 | } 28 | } 29 | 30 | 源集会表现的和在常规应用中所做的一样,否则你的应用和常规的应用就没区别了。但是 31 | ,一如既往的,Android类库项目不是用来创建一个APK文件的,而是作为一个类库的。 32 | 33 | ####依赖于类库项目 34 | 35 | 对于依赖一个类库项目你主要有两种选择: 36 | 37 | 1. 如果类库项目是你自己的,特别是当它只供给单个应用的时候,你可以把类库项目设置成 38 | 一个模块或者包含应用项目的子项目,就如我们会在下一节所看到的。 39 | 40 | 2. 你可以以一个AAR artifact的形式发布类库项目到一些仓库,例如一个本地仓库,然后 41 | 以依赖的形式引用AAR。artifact以及仓库的内容会在本章稍后出现。 42 | 43 | 这些不是互斥的。例如由本书作者发布的CWAC类库,就同时使用了这两种技术。这些项目以 44 | Android类库项目外加一个(或者多个)样例应用展示类库的使用。在debug构建中, 45 | 样例应用会以子项目的形式依赖类库。而在release构建中,样例应用依赖的是类库的所发布的AAR。 46 | 我们会在之后这章中了解到如何根据构建类型的不同而有不同的依赖。 47 | -------------------------------------------------------------------------------- /GradleandDependencies/Dependencies.md: -------------------------------------------------------------------------------- 1 | 依赖? 2 | 3 | 以防你之前在不知道依赖这个概念,在这章以及Gradle文档中,“依赖”意味着“你的项目所依赖的是位于 4 | 你的项目之外的"。 5 | 6 | 在Gradle构建的Android应用中,其中包括: 7 | 8 | * 本地JAR包 9 | * NDK-构建的本地Linux .so文件 10 | * 本地Android类库项目 11 | * 其它类型的子项目 12 | * 例如像Maven Center这样的仓库获取的"artifacts" 13 | 14 | 15 | -------------------------------------------------------------------------------- /GradleandDependencies/DependenciesByBuildType.md: -------------------------------------------------------------------------------- 1 | ###经由构建类型的依赖 2 | 3 | 一个构建类型可以有它自己的依赖。 4 | 5 | 依赖闭包中的compile声明是为所有构建类型所定义的。但是,每个构建类型有着它自己版本的compile 6 | 声明,像debugCompile,就会添加仅仅在debug构建类型使用的依赖。 7 | 8 | 如果你创建了你自己自定义的构建类型,注意你会需要在你build.gradle文件中在你的所定义的构建类型 9 | 之后加上依赖闭包。之后再Gradle定义了你的构建类型之后,你的自定义compile声明才可用。 10 | 11 | 也存在androidTestCompile,它定义了仅仅在测试的时候使用的。这在单元测试那章会有详细介绍。 12 | -------------------------------------------------------------------------------- /GradleandDependencies/DependenciesByFlavor.md: -------------------------------------------------------------------------------- 1 | ###经由‘Flavor’的依赖 2 | 3 | 相似的,如果你定义了多个`product flavor`,你就可以有雨某个特定‘flavor’绑定的依赖。 4 | 5 | 例如,假定你为多个可穿戴设备编写了一个应用,并且你设置了三个`product flavor`: 6 | 7 | productFlavors{ 8 | standard{ 9 | applicationId ="com.commonsware.android.wearable.qr" 10 | } 11 | imwatch{ 12 | applicationId "com.commonsware.android.wearable.qr.imwatch" 13 | } 14 | sony{ 15 | applicationId "com.commonsware.android.wearable.qr.sony" 16 | } 17 | } 18 | 19 | 包含以上productFlavors配置的android 闭包之后的 dependencies闭包可以有 20 | 一个有每种口味的混合以及口味特有的依赖:例如: 21 | 22 | dependencies{ 23 | compile 'com.android.support:support-v4:19.0.1' 24 | compile 'com.google.code.gson:gson:2.2.4' 25 | compile 'com.squareup.okhttp:okhttp:1.3.0' 26 | compile 'com.squareup.retorfit:retrofit:1.4.0' 27 | sonyCompile 'com.sonyericsson.extras.liveware.aef:SmartExtansionUntils:2.1.0' 28 | } 29 | 30 | 这里,最后一个依赖使用的是sonyCompile,而不是compile,只是这是一个专为sony产品口味使用的依赖。 31 | 32 | 注意这里为sonyCompile列出了的artifact并不真实存在,至少现在不存在。在到某个时间点SONY开始把 33 | 它们放在Maven Central或它们自己的artifact仓库之前,转换SONY的代码成本地的artifact, 34 | 然后通过mavenLocal()进行引用是有可能的。 35 | -------------------------------------------------------------------------------- /GradleandDependencies/DependenciesandtheProjectStructureDialog.md: -------------------------------------------------------------------------------- 1 | ###项目依赖和项目结构对话框 2 | 你可以使用项目结构对话框中的Dependencies页签来维护你的依赖,至少对较为简单的场景是可以的。 3 | -------------------------------------------------------------------------------- /GradleandDependencies/DependingUponNDKBinaries.md: -------------------------------------------------------------------------------- 1 | ###依赖于NDK二级制文件 2 | 3 | 对于Android来说是能够通过Gradle使用NDK的。但是,这是复杂的并且属于 4 | [用于Android的Gradle高级技巧那章](/FoucusOnNDK/README.md)。 5 | -------------------------------------------------------------------------------- /GradleandDependencies/DependingUponSubProjects.md: -------------------------------------------------------------------------------- 1 | ###依赖于子项目 2 | 3 | 在经典的Eclipse项目中,我们并没有子项目的概念。但是,Gradle和AndroidStudio都支持一种 4 | 包含一系列项目的顶层目录结构。 5 | 6 | 例如,Gradle/HelloMultiProject目录包含了: 7 | * 一个HelloLibraryConsumer项目 8 | * 一个包含一个Hellolibrary项目的libraries/子目录 9 | 10 | 在此情形中,HelloLibrary是一个Android类库项目,是来自在这章前面看到的 11 | build.gradle文件。HelloLibraryConsumer是一个常规的应用,它使用的 12 | 是HelloLibrary Android类库项目中的代码。 13 | 14 | 如果你的类库项目仅仅是被一个应用所使用的,你可能会选择这种方式组织你的代码。 15 | 16 | 顶层目录一定要有一个settings.gradle文件,其中列出目录中所能发现的Gradle项目 17 | (以及它的所有子目录)。 18 | 19 | include ':HelloLibraryConsumer',':libraries:HelloLibrary' 20 | 21 | 开头的:指的是总的根目录,所以:HelloLibraryConsumer指的是根目录下的HelloLibraryConsumer/ 22 | 目录。其它的:值代表的是层级结构中的等级,所以,:libraries:HelloLibrary/指的是 23 | libraries/HelloLibrary/subdirectory,而不是使用/,/在Gradle中另有用途。 24 | 25 | 因此,include声明告诉Gradle这个项目总共由两个子项目构成。 26 | 27 | 为了指示HelloLibraryConsumer想要使用来自HelloLibrary类库的代码,还有一行 28 | 要加到dependencies闭包中,来引用子项目: 29 | 30 | buildscript{ 31 | repositories{ 32 | mavenCentral() 33 | } 34 | dependencies{ 35 | classpath 'com.android.tools.build:gradle:2.1' 36 | } 37 | 38 | apply plugin:'com.android.application' 39 | 40 | dependencies{ 41 | compile project(':libraries:HelloLibrary') 42 | } 43 | 44 | android{ 45 | compileSdkVersion 19 46 | buildToolsVersion "21.1.2" 47 | } 48 | } 49 | 50 | 鉴于fileTree()是发现libs/目录中的JAR包,project(':libraries:HelloLibrary') 51 | 是识别子项目,并且我们告诉Gradle编译子项目到我们的项目中。 52 | 53 | 从根目录(那个有settings.gradle文件的目录),你可以运行整个应用的gradle 任务。 54 | 这在主要应用的目录中也有效(在此情形中,HelloLibraryConsumer/)。 55 | 56 | 虽然这个方式对一些应用来说是很好的,当类库可能被多个应用使用的时候这个结构可能不能很好工作。 57 | 特别是类库被其它作者所使用的时候。在这个情形中,类库需要以一个artifact的形式发布到 58 | 仓库,会在下一节涵盖到。 59 | -------------------------------------------------------------------------------- /GradleandDependencies/DependingUponaJAR.md: -------------------------------------------------------------------------------- 1 | ###依赖于一个JAR包 2 | 3 | 自2012年年初以来,Ant和Eclipse对于第三方JAR拥有着共同的规则:把它们放进你项目的libs/目录下, 4 | 两个构建环境都会从这个目录中取出jar包。具体来说,它们会: 5 | 6 | * 添加这些JAR包到运行时`classpath`,引用这些JAR包的公开API的你的代码会通过编译,并且 7 | * 添加这些JAR包内容到你的APK,在运行时你对这些JAR包类的引用能得到解析。 8 | 9 | 它是有效的。 10 | 11 | 新的基于Gradle的构建系统不会以同样的方式自动使用你的libs/目录下的内容。 12 | 这就是为什么build.gradle使用简单本地jar包,会需要动手写一个像这样的依赖闭包: 13 | 14 | dependencies{ 15 | compile fileTree(dir:'libs,include:'*.jar') 16 | } 17 | 18 | 19 | 这个fileTree()会遍历这个位于dir属性的目录树(这里的话是libs)并且寻找匹配包含通配符模式的文件 20 | (这里的话,*.jar)。 21 | 这会返回所有在libs/目录的jar文件,然后这些会添加到编译过程中。 22 | 23 | 虽然我们没有明确指示在生成的APK文件中包含这些JAR包,事实上已经作为android加工的一部分被处理了。 24 | 25 | 注意这是可配置的。所以,如果出于某些原因,你想让你的jar包位于libs/之外的目录,例如jars/或localDependencies/或wheeMarkingLongDirectroyNameIsFun/,你是可以这么做的。 26 | 27 | ####...为什么有些人不喜欢这个 28 | 29 | 但是无论如何,在没有更好的选择的时候,以这种方式使用简单的jar包是不被认可的。 30 | 31 | 其中一个原因是jar文件不一定包含关于这个jar文件版本的所有信息。jar包的更新是频繁,除非jar包的作者把 32 | 版本信息改进文件名中,不然你是不能光通过看一个jar包而辨别出它是新还是旧。 33 | 34 | 例如,经典的Android支持包的Jar包android-support-v4.jar。一些开发者看到了-v4这部分并, 35 | 就认为这个jar包是这个类库的第四版。实际上,-v4意味着它的类主要来自于android-support-v4, 36 | 并且且是为向后兼容至API等级4的应用而设计的。但是,这个包每隔几个月就会有新的类以及bug修复。 37 | 因此,两个叫做android-support-v4.jar可能有着完全不同的内容,例如一个是2011年而一个是2013年。 38 | 39 | 这就是造成Ant/Eclipse构建过程在遇到多个相同jar文件的时候中断的原因(例如,同名的JAR包 40 | 分别存在于你的项目和项目类库项目中)。单凭名字是无法区分它们是否相同的。构建工具会使用MD5散列来 41 | 判断内容是不是真正的一模一样,这有效但却不是一个理想的解决方案。 42 | 43 | 另一个人们不认可的原因是没有东西来管理jar包本身的依赖。很多时候一个jar包依赖于其它jar包, 44 | 但是这个jar包没有表达这个的依赖方式。换言之,开发者应该自己管理好它们的jar包,可能是通过阅读文档 45 | 并遵循指导意见。但是,开发者不一定会读文档或遵循这些指导的,手工的依赖管理危机重重。 46 | 47 | 在传统的Java开发中,"artifacts"和“repositories”被引入来帮助提供围绕JAR的一些元数据封装。 48 | 为了帮助开发者找到正确版本以及判断什么时候更新。使用“artifacts”和“repositories”为Gradle所推荐。 49 | 正如在这章之后内容看到的,Gradle会使使用这些结构变得相对简单。 50 | -------------------------------------------------------------------------------- /GradleandDependencies/PrerequisitesandWarning.md: -------------------------------------------------------------------------------- 1 | ###准备工作和警告 2 | 3 | 理解这章的内容需要你已经读过[Gradle介绍](/IntroducingGradleandTheManifest/README.md)那章 4 | 以及涵盖基础Gradle/Android集成的[旧式项目结构](/GradleandEclipseProject/README.md)和 5 | [新项目结构](/GradleandtheNewProjectStructure/README.md)。 6 | -------------------------------------------------------------------------------- /GradleandDependencies/README.md: -------------------------------------------------------------------------------- 1 | ##Gradle和依赖 2 | John Donne 写过这么一句话,没有人是一座孤岛。现如今,几乎没有应用是一座孤岛。 3 | 很少有应用能完全避免使用第三方代码库的。大都数应用需要一个来自Android支持包的向后 4 | 兼容或其它类(例如,ViewPager),或者会依赖于`Paly Services SDK`,或者会使用很多第三方jar包 5 | 和Android类库项目。 6 | 7 | 好消息是在你构建你的应用的时候,Gradle添加了很多用于引用这些第三方代码库的能力。虽然它稍微增加 8 | 了小部分重用(一个jar包)的复杂性,但是它能很大程度上简化“大型的重用”(例如,一些Android类库项目)。 9 | 10 | 这章会概述你的应用可以拥有的“依赖”种类以及你该如何配置`Gradle`让其支持它们。 11 | 12 | 注意:这章所描述的项目不是能被Eclipse使用的,因为在写这部分内容的时候Eclipse并不支持Gradle。 13 | 14 | 目录: 15 | * [准备工作和警告](/GradleandDependencies/PrerequisitesandWarning.md) 16 | * [依赖?](/GradleandDependencies/Denpendencies.md) 17 | * [两个依赖闭包的故事](/GradleandDependencies/ATaleofTwoDenpendenciesClosures.md) 18 | * [依赖于JAR包](/GradleandDependencies/DenpendingUponaJAR.md) 19 | * [依赖于NDK二进制文件](/GradleandDependencies/DependingNDKBinaries.md) 20 | * [依赖于一个Android类库项目](/GradleandDependencies/DependingUponAndroidLibraryProject.md) 21 | * [依赖于子项目](/GradleandDependencies/DependingUponSubProjects.md) 22 | * [依赖于`Artifacts`](/GradleandDependencies/DependingUponArtifacts.md) 23 | * [从Gradle创建JAR包](/GradleandDependencies/CreatingAdnroidJARsfromGradle.md) 24 | * [经由构建类型的依赖](/GradleandDependencies/DependenciesByBuildType.md) 25 | * [经由`Flavor`的依赖](/GradleandDependencies/DenpenciesByFlavor.md) 26 | * [一个传递依赖的特性](/GradleandDependencies/APropertyofTransitive.md) 27 | * [分析一些`CWAC`构件](/GradleandDependencies/ExaminingSomeCWACBuilds.md) 28 | * [依赖和项目结构对话框](/GradleandDependencies/DependenciesandtheProjectStructureDialog.md) 29 | -------------------------------------------------------------------------------- /GradleandEclipseProject/CreatingYourGradleBuildFile.md: -------------------------------------------------------------------------------- 1 | ###创建你的Gradle构建文件 2 | 3 | 你需要一个`build.gradle`文件才能使用`Gradle`构建你的项目。 4 | 5 | 正如在介绍`Gradle`那章中提及到的,`Gradle`是给Android Studio的原生构建系统。 6 | 因此,如果你使用这个集成开发工具的话,你应该必然会获得一个`build.gradle`文件。同样的, 7 | 如果你从Eclipse迁移到AndroidStudio的话,使用Android Studio导入向导,因为它比你自己弄的好, 8 | 并且会帮助把你的代码组织成Android Studio原生使用的基于源集的项目结构。 9 | 10 | 现如今即使你使用的不是Android Studio,也有两种获取`build.grdle`文件方法: 11 | 从Eclipse项目导出或手动创建。理论上来说从Eclipse上导出是最好的。但是要是使用的Eclipse不支持的话, 12 | 你可能就要全部手动创建了。毕竟,正如你看到的,你从Eclipse导出过程得到的东西已经过时了。 13 | 14 | ####从Eclipse导出 15 | 如果你已有一个Eclipse项目,获取`build.gradle文件`给项目的最简单的方式是让ADT插件导出一个给你。 16 | 17 | ####执行导出 18 | 为了导出build.gradle文件,要么选择Eclipse主菜单上的File>Export,要么选择包浏览器中的上下文 19 | 菜单的“Export”。不管是哪个,应该会带来一个向导样式的对话框,让你选择你要导出什么: 20 | 21 | 这里,选择“Generate Gradle build files”.如果没有这一选项的话,你可能用的是较老版本的ADT插件并且需要更新。 22 | 23 | 点击下一步会带出一个包含所有安装的项目列表,从中你会需要勾选你要导出的项目: 24 | 25 | 注意,由于向导中的一个bug,你的项目可能没有选中。 26 | 27 | 一旦你选择了项目,下一步的按钮应该就能点击了。点击它会弹出一个确认向导页: 28 | 29 | 它应该显示你在向导中勾选的项目。这里,有一个强制覆盖已存在文件的勾选框- 30 | 在你之前导出过`Gradle`文件并且希望将用新导出的文件取代它们的时候使用。 31 | 32 | 点击完成按钮会做导出的工作并且带来一个报告页面 33 | 34 | 在仔细回顾摘要之后(或仅仅只是忽略了),点击完成关闭向导。 35 | 36 | ####生成了什么 37 | 你要费心的是: 38 | * 一个`build.gradle`文件 39 | * 就像之前那章讨论的一样,`Gradle wrapper`,是以gradlew和/或gradlew.bat文件和gradle子目录 40 | 的形式存在的。如果你不使用wrapper的话,除了gradle-wrapper.properties文件之外可以随意删除这些文件。 41 | * 一个隐藏的.gradle目录,包含了Gradle构建过程的缓存数据,例如`build.gradle`文件的解析副本, 42 | 如果上次运行之后你没有修改build.gradle文件的话就能运行更快。 43 | 44 | ####需要修补的 45 | 为了能让结果产生的项目能很好地使用Android Studio,改变如下: 46 | 47 | * Android插件的版本改为1.0或者更高 48 | * 应用插件声明语句从‘android'改成‘com.android.application' 49 | * 在gradle/wrapper/gradle-wrapper.properties文件中的`distributionUrl`改成https:\//service.gradle.org/distributions/gradle-2.2.1-all.zip 50 | -------------------------------------------------------------------------------- /GradleandEclipseProject/ExaminingtheGradleFile.md: -------------------------------------------------------------------------------- 1 | ###分析Gradle文件 2 | 这本书的样例代码包含了一个`Gradle/Hello`样例项目。这只是一个由Eclipse新项目向导创建的一个“hello, 3 | world”应用。 4 | 5 | 但是,它也包含了一个由Eclipse导出的build.gradle文件。 6 | 7 | buildscript{ 8 | repostories{ 9 | mavenCentral 10 | } 11 | dependencies{ 12 | classpath 'com.android.tools.build:gradle:1.0.0' 13 | } 14 | } 15 | apply plugin: 'com.android.application' 16 | 17 | dependencies{ 18 | compile fileTree(dir:'libs',include:'*.jar') 19 | } 20 | 21 | android{ 22 | compileSdkVersion 19 23 | buildToolsVersion "21.1.2" 24 | sourceSets{ 25 | main{ 26 | mainfest.srcFile 'AndroidManifest.xml' 27 | java.srcDirs=['src'] 28 | resource.srcDirs=['src'] 29 | aidl.srcDirs=['src'] 30 | renderscript.sirDirs=['src'] 31 | res.srcDirs=['res'] 32 | assets.srcDirs=['assets'] 33 | } 34 | //Move the tests to tests/java,tests/res,etc.... 35 | instrumentTest.setRoot('tests') 36 | 37 | //Move the build types to build-types/ 38 | insrumentTest.setRoot('tests') 39 | 40 | //Move the build types to build-tyes/ 41 | //For instance,build-types/debug/java,build-types/debug/ AndroidManifest.xml,... 42 | //This moves them out of them default location under src//...which would 43 | //confilct with src/ being used by the main source set. 44 | //Adding new build types or product falvaors should be accompanied 45 | //by a similar customization 46 | debug.setRoot(‘build-type/debug’) 47 | release.setRoot('build-typs/release') 48 | } 49 | } 50 | 51 | 这个文件中的大部分内容都已经在Gradle介绍那章涵盖到了。没有涵盖到的是sourcesets闭包-会在[紧接着的章回]()涵盖到。 52 | -------------------------------------------------------------------------------- /GradleandEclipseProject/Legacy.md: -------------------------------------------------------------------------------- 1 | ###"旧式"? 2 | 3 | 这里,“旧式目录结构”意味着有点像这样的项目树: 4 | 5 | 它由一个传统的`Java src`树支配,外加像res/,AndroidManifest.xml等Android特有项。 6 | 7 | 这个目录结构能很好地使用Gradle,并且为了维护和其它像Eclipse这样的工具的兼容性, 8 | 你可能需要保持这个结构一段时间。 9 | -------------------------------------------------------------------------------- /GradleandEclipseProject/PrerequisitesandWarnings.md: -------------------------------------------------------------------------------- 1 | ###准备工作和警告 2 | 理解这章需要你已经读过[介绍Gradle那章](/IntroducingGradleandTheManifest/README.md) 3 | -------------------------------------------------------------------------------- /GradleandEclipseProject/README.md: -------------------------------------------------------------------------------- 1 | ##Gradle和Eclipse项目 2 | 3 | 项目主要分两种,那些使用新式`Gradle特有`目录结构的,和那些自2008沿用至2013年(在一定程度上 4 | 甚至更久)-大部分项目是使用Eclipse创建的。 5 | 6 | 但是,Gradle在两种目录布局中都是能够胜任构建项目的工作的。这章会分析如何添加`Gradle`支持到到 7 | Eclipse Android项目中的同时不改变你的目录结构。 8 | -------------------------------------------------------------------------------- /GradleandTasks/KeyBuild-RelatedTasks.md: -------------------------------------------------------------------------------- 1 | ###关键构建相关任务 2 | 3 | 为了找出什么任务是你可用的,你可以从项目目录中运行`gradle`任务。这就会导致类似如下的输出: 4 | 5 | :tasks 6 | 7 | ---------------------------------------------------- 8 | 9 | All tasks runnable from root project 10 | 11 | -------------------------------- 12 | 13 | Android tasks 14 | 15 | ------------- 16 | 17 | androidDependencies - Displays the Android dependecies of the project 18 | signingReport - Displays the signing info for each vairiant 19 | 20 | Build tasks 21 | 22 | --------------- 23 | assemble - Assembles all variants of all applications and secondary packages. 24 | assembleDebug-Assemables all Debug builds 25 | assembleDebugTest - Assembles the Test build for the Debug build 26 | assembleRelase - Assembles all Release builds 27 | build - Assembles and tests this project 28 | buildDependents - Assembles and tests this project and all projects that depend on it. 29 | buildNeeded - Assembles and tests this project and all project it depends on. 30 | clean - Deletes the build directory 31 | 32 | Build Setup tasks 33 | 34 | ------------------ 35 | init - Initializes a new Gradle build.[incubating] 36 | wrapper - Generates Gradle wrapper files.[incubating] 37 | 38 | Help tasks 39 | 40 | ------------------ 41 | components-Displays the components produced by the root project 'Decktastic'.[incubating] 42 | dependencies-Displays all dependencies declared in root project 'Decktastic'. 43 | dependencyInsight-Displays the insight into a specific dependency in root project 'Decktastic' 44 | help-Displays a help message 45 | projects-Displays the sub-projects of root project 'Decktastic' 46 | projecties-Displays the properties of root project 'Decktastic' 47 | tasks-Displays the tasks runnable from root project 'Decktastic' 48 | 49 | Install taks 50 | 51 | ------------- 52 | installDebug-Installs the debug build 53 | installDebugTest-Installs and runs the tests for Build 'debug' on connected devices. 54 | connectedCheck - Run all device checks using Device Provider and Test Servers. 55 | lint - Runs lint on the Debug build 56 | lintDebug -Runs lint on the Debug build 57 | lintRelease - Runs lint on the Release build 58 | 59 | Other tasks 60 | 61 | ------------ 62 | compileDebugSource 63 | compileDebugSource 64 | compileReleaseSource 65 | 66 | Rules 67 | 68 | ----------- 69 | Pattern:clean:Cleans the output files of a task. 70 | Pattern:build:Assembles the artifacts of a configuration 71 | Pattern:upload:Assembles and uploads the artifacts belonging to a configuration. 72 | 73 | To see all tasks and more detail,run with --all. 74 | 75 | BUILD SUCCESSFUL 76 | 77 | Total time:9.669 secs 78 | 79 | 这个列表是根据`build.gradle`的内容自动生成的,尤其是包含由com.android.application插件所定义的任务。 80 | 81 | 原则上说,你应该运行任务的时候详述整个任务名。但是,只要它能唯一地对任务进行识别,你就能使用简写。 82 | 83 | 至少短期来说,开发者会使用的最常见的任务是installDebug.这会构建一个调试模式的应用并将其安装在 84 | 一个可用的设备或模拟器上。这大致是跟基于ant命令行构建的ant install debug对应的。 85 | 86 | 只要有installDeubg,那就有installRelease.任务的Debug和Release部分不是硬编码的,而是源于 87 | 定义在build.gradle文件中的"build types"。概念以及规则和用法会在下一章涵盖到。但是, 88 | 默认情况下installRelease是没有的,因为安装应用需要的是签名过的APK,并且用于Android的`Gradle` 89 | 不知道如何对它进行签名。同样我们会在下一章讲到。 90 | 91 | 如果你仅仅想要构建应用,却不安装它,assembleDebug(aD)或assmbleRelease(aR)会达到这个目标. 92 | 如果你要从真机或模拟器上卸载应用,unintallDebug(uD)和uninstallRelease(uR)应该有用。 93 | 94 | 至于其它任务,例如“check”任务,会在之后的章回涵盖到。 95 | -------------------------------------------------------------------------------- /GradleandTasks/README.md: -------------------------------------------------------------------------------- 1 | ##`Gradle`和`Tasks` 2 | `build.gradle`文件教导`Gradle`如何执行多个任务,例如如何编译一个Android项目。 3 | 在一个能感知`Gradle`的集成开发环境(AndroidStudio)之外,你使用`Gradle`运行这些任务。 4 | 如果你自己安装了`Gradle`拷贝,你会`gradle`命令行;如果你依赖于一个被信任的Gradle Wrapper拷贝, 5 | 你会使用你项目根目录下的./gradle脚本。 6 | 7 | 出于这本书的目的,`gradle`命令行仅仅是以./gradlew的替代品出现,在你使用`Gradle Wrapper`脚本的 8 | 地方可以用`gradle`命令行替代./gradlew。 9 | -------------------------------------------------------------------------------- /GradleandTasks/Results.md: -------------------------------------------------------------------------------- 1 | ###结果 2 | 3 | 使用Eclipse的话,构建结果会到bin/目录,并生成源代码(例如R.java)到gen/目录。 4 | 使用Gradle的话,所有的输出结果都会到build/目录。 5 | 6 | 具体来说,你的apk文件生成到build/outputs/apk目录中。因构建行为是debug还是release而构建生成 7 | 不同的APK版本。 8 | 9 | Gradle有一个清理build/目录的clean任务。但是,注意Eclipse不使用build/目录, 10 | 所以`Gradle clean`操作不会清理Eclipse使用的预编译类。 11 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/AddingBuildTypes.md: -------------------------------------------------------------------------------- 1 | ###添加构建类型 2 | 对很多开发者而言,加上之前展示的一些调整,debug和release构建类型就够用了。尽管如此,少数开发者会有需要新类型的其它情景。幸运的是,添加一个新的类型是相当简单的,就如在Gradle/HelloBuildType样例项目中看到的,基于之前的样例中添加一个新的构建类型。 3 | 4 | 如同内置的构建类型一样,通过在src/目录下添加适当的目录,你的新的构建类型也能有它们自己的源集。并且,如同内置的构建类型一样,你可以在build.gradle的buildTypes闭包中配置新的构建类型。 5 | 6 | buildscript{ 7 | repositories{ 8 | mavenCentral() 9 | } 10 | dependencies{ 11 | class 'com.android.tools.build:gradle:1.0.0' 12 | } 13 | } 14 | 15 | apply plugin: 'com.android.application' 16 | 17 | dependencies{ 18 | } 19 | 20 | android{ 21 | compileSdkVersion 19 22 | buildToolVersion "21.1.2" 23 | 24 | defaultConfig{ 25 | versionCode 2 26 | versionName "1.1" 27 | minSdkVersion 14 28 | targetSdkVersion 18 29 | } 30 | 31 | signingCofigs{ 32 | release{ 33 | storeFile file("HelloCofig.keystore") 34 | keyAlias "HelloCofig" 35 | storePassword 'laser.yams.heady.testy' 36 | keyPassword 'fw.stabs.steady.wool' 37 | } 38 | } 39 | 40 | buildTypes{ 41 | debug{ 42 | applicationIdSuffix ".d" 43 | versionNameSuffix "-debug" 44 | } 45 | release{ 46 | siningConfig signingConfigs.release 47 | } 48 | mezzanine.initWith(buildTypes.release) 49 | mezzanine{ 50 | applicationIdSuffix ".mezz" 51 | debuggable true 52 | } 53 | } 54 | 55 | 在这个项目中,我们要第三个叫作mezzanine的构建类型,代表处于debug构建和release构建之前的中间地带。 56 | 57 | 为了告诉Android新的构建类型,我们需要初始化一个。这个mezzanine.initWith(buildTypes. release)声明进行处理的,它是在已经定义好的release构建版本之上初始化新的mezzanine构建版本。从那里开始,随后的mezzanine闭包就可以修改构建类型的属性了。在此例中我们: 58 | 59 | * 在包名之后加上了一个.mezz后缀 60 | * 标记项目为可调试 61 | * 使用release的签名秘钥 62 | 因为我们是以release构建的配置开始的,实际结果就是我们有了一个等同于release构建的构建,仅仅是设置了下debuggable标记。 63 | 64 | 现在,我们得到了带着Mezzagnie的Gradle任务,像installMezzagnie,和Debug和Relase对应部分一起。 65 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/CreatingaProjectintheNewStructure.md: -------------------------------------------------------------------------------- 1 | ###创建一个新结构的项目 2 | 在写这段的时候,主要有两种方式把项目弄成新的项目结构:使用Android Studio或者手动创建。 3 | 4 | 正如在这本书最早的章节提到的,Android Studio的原生构建系统是Gradle和给Gradle的`Gradle Android` 5 | 插件。当你通过集成开发环境创建一个新的项目的时候,它会自动设置成新的项目结构。 6 | 7 | 不幸的是,写到这段的时候,没有从Eclipse中把项目组成成新结构的方法,只是因为Eclipse不支持新的结构。 8 | 同样的,也没有类似于android create project这样的命令行工具会创建一个Gradle项目。 9 | 10 | 因此,短期来说,如果你不使用AndroidStudio,并且你想要新结构的项目,你自己需要手动创建目录树和build.gradle文件。 11 | 这可能要从零开始,或者是从现有源代码中复制项目结构。Martin Liersch(又名,"Goddchen")发布了一个有多种样例项目的Github库。 12 | 你可以将它和呈现在本章剩余部分的样例作为灵感源泉。 13 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/DoingtheSplits.md: -------------------------------------------------------------------------------- 1 | ###做分离 2 | 给Android的Gradle 0.13 引进了splits,作为产品风格在两种情形下的轻量级灌装替换: 3 | 4 | * 不同的APK文件有不同的NDK二进制文件 5 | * 不同的APK文件针对特定的屏幕密度,这对那些有很多图片并突破发行渠道的上限。(例如,PlayStore上是100MB的限制,较早之前是50MB的限制) 6 | 7 | 作为一个开发者你所要是在有限配置下,实现特定的分离。注意,你没有分开的Gradle配置(例如,applicationId)以及源集给分离(splits)。这就允许分离在构建的时候处理地更快,因为构建工具 可以做一些简化假定并且避免了重新编译。 8 | 9 | ####列出分离的范围 10 | 分离,默认情况下,会每个可能的类型输出一个APK。例如,在密度上分类会给你为ldpi,mdpi,hdpi,xhdpi,xxhdpi和xxxhdpi生成一个APK。另外,密度这种情况下,你也获得了一个包含默认支持所有密度的“universal”APK。 11 | 12 | 这样很好...但是如果你不需要为所有这些密度生成APK?例如,你没有装载tvdpi资源,就没有必要为它设置一个hdpi APK。 13 | 14 | 有两种基本控制构建范围的模式: 15 | 16 | 使用exclude声明,在初始默认的上移除一些选项 17 | 使用reset()方法抹除默认的,然后使用include声明列出你想要的。 18 | 换句话说,exclude实现了一个黑名单,reset()/include的组合实现了白名单。所有一切都一样,白名单可能是更好的选择,那么你可以指出什么在你的应用中写了。 19 | 20 | ####要求NDK分离 21 | 在你的android闭包中,你可以添加一个包含一个abi闭包的splits闭包,它按CPU架构顺序设置APK。 22 | 23 | splits{ 24 | abi{ 25 | enable true 26 | reset() 27 | include 'armeabi-v7a','x86' 28 | universalApk true 29 | } 30 | } 31 | 32 | 这里,我们: * 打开了split(enable true) * 移除了默认包含的abi * 列出了你要包含的ABI(包含‘armeabi-v7a','x86') * 要求也生成一个“全体的APK”,包含所有的ABI(universalApk true) 33 | 34 | 后者对不允许为不同CPU架构上传多个APK的发行渠道是很有用的。这样,你至少能把你的应用发布到那,即使占用了更多的磁盘空间。默认情况下,由于CPU架构,你不会得到一个“全体APK”。 35 | 36 | ####要求密度分离 37 | 相同的基本模式在密度上也适用: 38 | 39 | splits{ 40 | density{ 41 | enable true 42 | reset() 43 | include 'hdpi', 'xhdpi', 'xxhdpi' 44 | } 45 | 46 | 再一次,我们打开分离,重置默认,然后选择我们要的密度。 47 | 48 | 注意,虽然,“全体APK”总是会为所有的密度生成。我们不需要有universalApk true,并且当前universalApk false不是一个可选项。 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/Falvors,Build,andtheProjectStructureDialog.md: -------------------------------------------------------------------------------- 1 | 风格,构建变种,和项目结构对话框 2 | 欢迎使用项目结构中的构建类型和产品风格标签来维护你的build.gradle文件的这些部分,至少对简单的场景是可以的。 -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/ObjectivesoftheNewProjectStructure.md: -------------------------------------------------------------------------------- 1 | ###新项目结构的那些对象 2 | 3 | 在起初的时候,Android 应用往往是相当简单的,因为我们只有为数不多的几个设备,少数用户, 4 | 一个主要分发渠道(Android市场),Android生态系统中几乎没有较大的投资。 5 | 6 | 如今情况变了。 7 | 8 | 现在,公众的Android应用可以是非常复杂的,更不用说企业内部使用的(作为由企业开发的副作用)。 9 | 我们有着多个分发渠道,例如Amazon Android应用市场和Yandex市场。10亿设备和将近10亿的用户。 10 | 大小品牌都蜂拥到Android,也给它们自己带来了挑战。 11 | 12 | 新的构建系统是了简化构建复杂的Android应用过程而设计的,但是,理想状态下不是使制作 13 | Android应用更加困难。它是为像这样的场景设计的: 14 | 15 | * 支持多个分发渠道,这可能需要多个应用内部支付引擎 16 | * 支持应用自定义,例如被不同企业使用 17 | * 支持真的需要为不同设备打包不同apk的应用,而不是由单个apk支持全部的。 18 | * 支持应用作为大得多的集成系统的一部分并且作为大系统的一个包 19 | * 支持基于常用代码,资源,第三方库诸如此类的应用 20 | * 等等 21 | 22 | 结合Android Gradle插件和Gradle,虽然有一定的学习曲线,新项目结构使这些都变得可能。 23 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/PrerequisitesandWarnings.md: -------------------------------------------------------------------------------- 1 | ###准备工作和警告 2 | 3 | 理解这章的内容需要你的已经读过了[介绍Gradle这章](/IntroducingGradleandTheMainfest/README.md), 4 | 并了解基本的Gradle/Android集成,以及了解[Gradle在旧式项目结构的使用](GradleandtheEclipse/README.md)等内容。 5 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/README.md: -------------------------------------------------------------------------------- 1 | ##Gradle和新项目结构 2 | 3 | 前一章展示了如何使用Gradle,以及Android Gradle插件,用命令行,Eclipse,ItelliJ IDEA,Ant 4 | 等构建项目。 5 | 6 | 虽然传统的项目目录结构能用,但是它并不能让发挥Android Gradle插件的全部威力。为了利用新构建系统 7 | 的灵活性,你将需要以稍微有点不同的方式组织你的`source`,`resources`,`assets`以及相关的文件。 8 | 9 | 这章会列出这个“新的项目结构”的概要,并向你展示给Android的Gradle的`build type`和`product flavors` 10 | 是如何让你更简单地从单个尽管重组的项目树得到多种形式的输出。这个项目结构是AndroidStudio来说是原生的, 11 | 所以Android Studio项目已经做好了支持这些种类的高级功能的准备了。 12 | 13 | 注意:这章所描述的项目不再能被Eclipse使用了,因为Eclipse不支持Gradle。 14 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/RevisitingtheLegacyGradleFile.md: -------------------------------------------------------------------------------- 1 | ###再访旧式的Gradle文件 2 | 3 | 鉴于这一切,让我们再次访问从Eclipse导出的build.gradle文件。 4 | 5 | buildscript{ 6 | repositories{ 7 | mavenCentral 8 | } 9 | dependencies{ 10 | classpath 'com.android.tools.build:gradle:1.0.0' 11 | } 12 | } 13 | 14 | apply plugin: 'com.android/application' 15 | 16 | dependencies{ 17 | compile fileTree(dir:'libs',include:'*.jar') 18 | } 19 | 20 | android{ 21 | compileSdkVersion 19 22 | buildToolsVersion "21.1.2" 23 | 24 | sourceSets{ 25 | main{ 26 | manifest.srcFile 'AndroidManifest.xml' 27 | java.srcDirs=['src] 28 | } 29 | } 30 | } 31 | 32 | 导出的build.gradle文件中大量android相关的配置在android闭包的sourceSets闭包中。在这里,我们指定什么应该被编译。 33 | 34 | Gradle让当前分开的全部扔到src/中,包括java代码,AIDL接口定义RenderScript源文件,以及java形式的资源(不要和android资源混淆)。因为这个构建文件是给传统的目录结构的,这些类型的输入文件依然会在src/目录中,所以main源集把android指向每一个的src目录。此外,main指示了minifest文件的名称以及res/和asssets目录树的位置。 35 | 36 | setRoot()调用储备的debug和release构建类型来指示它们的源集。如果它们存在,应该在分开的build-types/目录中,就跟被java源代码使用的src/位置一样。 -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/Terminology.md: -------------------------------------------------------------------------------- 1 | ###专有名词 2 | 为了理解新的项目结构带来了什么,我们需要从Gradle和给Gradle的Gradle Android插件定义一些专有名词。 3 | 4 | ####源集(Sourcesets) 5 | 引用Gradle文档的一句话:"源集只不过是源文件的一个群组,它是一起编译和执行的。"在这里,“源”意味着 6 | 所有你为应用创建的输入,例如java源代码,Android资源和manifest文件等等。与之形成对比的是依赖, 7 | 这个输入你通常是从其它开发者那得到的,例如可复用库。 8 | 9 | 源集它们本身没有特别的语意。你的项目可以选用单个或多个源集来组织你的代码。你可能因以下原因而有不同的源集: 10 | 11 | * 产品代码对测试代码,取代之前在Android开发中的分开的测试项目。 12 | * 接口代码对实现代码 13 | * 应用内不同的主要功能模块,尤其是如果它们是分开的小组或开发者对其进行维护的。 14 | * 等等 15 | 正如我们看到的,新的项目结构假定至少存在一个源集,通常叫做main,但是新的构建系统的其它特性 16 | 会包含另外源集。 17 | 18 | ####构建类型(Build Types) 19 | 构建类型是构建过程中产生的一个可选的轴线。 20 | 21 | 默认情况下,Gradle的Android 插件假定你要两种构建类型:release和debug。这两个类型可能经历不同的构建步骤 22 | ,例如应用ProGuard到release构建但是在debug构建的时候跳过。 23 | 24 | 使用Eclipse的话,这两种构建类型是焊死的,你有且只有它们两种,并且你在构建工具上进行不同自动配置的能力是有限的。 25 | 26 | Gradle的Android插件尽管允许构建类型有着配置上细微的区别,例如在包名后面加上一个.debug后缀, 27 | 所以你可以同时在同个设备上有着你应用的relase和debug版本。你也可以为处理不同的场景创建新的构建类型。 28 | 新的构建系统文档,例如,建议一个单独的“jnidebug”构建类型,在这里你可以指定项目的Linux .so文件在debug模式的编译。 29 | 30 | 正如我们看到的,创建你的构建类型包含对build.gradle文件的修改和添加对应的源集。 31 | 32 | ####产品风格(Product Flavors) 33 | 构建类型是改变你输出的一个轴线。产品风格是另一个改变你输出的独立轴线。 34 | 35 | 产品风格是你想要给不同情况以不同release输出的情景设计的。例如。你可能想要你的应用的一个版本使用Google的应用内支付API(用于PlayStore发行),另外一个应用版本使用Amazon的应用内支付API(用于Amazon Android应用市场发行)。在这种情况下,两者应用版本有release形式,并且你可能希望也有独立的debug构建版本。并且这两个版本应用的大部分代码是一样的。但是,不同的发行版本会有不同的代码-不仅正确的代码运行在正确的渠道,而且在发行的时候,渠道较之其他渠道没有特定的值。 36 | 37 | 另一个例子是一个应用被标明和配置给不同企业用户。你可以在很多的网页应用中看到这种情况-商贩卖出被标明和配置的网页应用版本给用户,不管这个应用运行在商家提供的设备还是消费者提供的设备上。同样的,应用的制作商收集员工时间表可能想要提供给它的消费者他们的时间表应用版本故意显示用户的标识,于用户特定的时间表相联系,基于客户如何使用时间表打开或关闭功能。但是,代码的大部分是被所有客户共享的,所以当应用更新或添加新特定或修补bug的时候,新的构建是所有用户所需的。在此例中,每个用户可以设置成一个独立的产品风格,共享大部分代码,轻微不同的代码,资源(例如,logo),以及基于客户需求的配置。 38 | 39 | 产品风格是可选的。如果你在你的build.gradle文件中没有描述人和产品风格,它是假定你有一个默认单独的产品风格。很多应用不需要产品风格,这个一个需要的时候才选择的特性。 40 | 41 | 正如我们看到的,创建一个新的产品风格包含对build.gradle文件的修改和添加对应的源集。 42 | 43 | ####构建变种 44 | 构建变种这个术语是用于构建类型和产品风格的向量积的。所以,一个有debug和release构建类型以及google和amazon产品风格的项目,默认会产生总共四种构建变体: 45 | 46 | 1.debug+google 47 | 48 | 2.debug+amazon 49 | 50 | 3.release+google 51 | 52 | 4.release+amazon 53 | 54 | ####风格维度(Flavor Dimensions) 55 | 有时候,即使这样也是不够灵活的,例如在这节稍前描述的google和amazon的情形。或者,如果获取优质版本应用必须要有预付的费用的时候,你可能需把免费和付费版本分开。 56 | 57 | 默认,产品风格是单个“风格方面”的一部分。但是,你可以把你的风格组织进你的独立的风格维度。(例如,一个是针对免费还是付费的,一个是针对发布渠道的。) 58 | 59 | 这些然后就在决定你构建变种的叉积上添加了另一个元素。假定我们又一个dist风格方面,由free和paid产品风格,以及由google和amazon风格组成的渠道风格维度。现在,当计算构建类型的时候,我们一共有8种可能的构建变种: 60 | 61 | 1.debug+google+free 62 | 63 | 2.debug+amazon+free 64 | 65 | 3.release+google+free 66 | 67 | 4.release+amazon+free 68 | 69 | 5.debug+google+paid 70 | 71 | 6.debug+amazon+paid 72 | 73 | 7.release+google+paid 74 | 75 | 8.release+amazon+paid 76 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/WhattheNewProjectStructureLooksLike.md: -------------------------------------------------------------------------------- 1 | ###新的项目结构是什么样的 2 | 3 | 有了这些知识背景,让我们看下“Gradle/helloNew”这个样例项目。这个项目开始是个Eclipse项目, 4 | 然后通过Eclipse导出向导有了个build.gradle文件。尽管之后,它会被重组成适应新的项目结构。 5 | 6 | ####目录树 7 | 预先组织好的项目目录树是相当传统的,只是添加了一些Gradle特性文件: 8 | 9 | Hello 10 | |--AndroidManifest.xml 11 | |--assets/ 12 | |build.gradle 13 | |libs/ 14 | | |--android-support-v4.jar 15 | |-- local.properties 16 | |-- proguard-project.txt 17 | |-- project.properties 18 | |-- res/ 19 | |-- |drawable-hdpi/ 20 | | |--drawable-hdpi/ 21 | | | |--ic_launcher.png 22 | | |-- drawable-ldpi 23 | | |-- drawable-mdpi 24 | | | |--ic_launcher.png 25 | | |-- drawable-xhdpi 26 | | | |--ic_launcher.png 27 | | |--layout/ 28 | | | |--activity_main.xml 29 | | |--menu 30 | | | |--main.xml 31 | |-- |values/ 32 | |-- |-- dimens.xml 33 | |-- |-- strings.xml 34 | |-- |-- styles.xml 35 | |-- values-sw600dp/ 36 | | |--dimens.xml 37 | |-- values-sw720dp-land/ 38 | | |--dimens.xml 39 | |-- values-v11/ 40 | | |--styles.xml 41 | |-- values-v14 42 | |--styles.xml 43 | |--src/ 44 | |-- com/ 45 | |--commonsware/ 46 | |--android/ 47 | |--gradle/ 48 | |--hello/ 49 | |--MainActivity.java 50 | 51 | 52 | (注意:以上列表只包含了当前讨论的相关内容) 53 | 54 | 新的项目结构,就有点不同了: 55 | 56 | 57 | HelloNew 58 | 59 | |-- build.gradle 60 | |-- libs/ 61 | | |--android-support-v4.jar 62 | |-- local.properties 63 | |-- proguard-project.txt 64 | |-- project.properties 65 | |-- src/ 66 | |-- main/ 67 | |--AndroidManifest.xml 68 | |--assets/ 69 | |--java/ 70 | | |--com/ 71 | | |--commosware/ 72 | | |--android/ 73 | | |--gradle/ 74 | | |--hello/ 75 | | |-- 76 | MainActivity.java 77 | |-res/ 78 | |-- |drawable-hdpi/ 79 | | |--drawable-hdpi/ 80 | | | |--ic_launcher.png 81 | | |-- drawable-ldpi 82 | | |-- drawable-mdpi 83 | | | |--ic_launcher.png 84 | | |-- drawable-xhdpi 85 | | | |--ic_launcher.png 86 | | |--layout/ 87 | | | |--activity_main.xml 88 | | |--menu 89 | | | |--main.xml 90 | |-- |values/ 91 | |-- |-- dimens.xml 92 | |-- |-- strings.xml 93 | |-- |-- styles.xml 94 | |-- values-sw600dp/ 95 | | |--dimens.xml 96 | |-- values-sw720dp-land/ 97 | | |--dimens.xml 98 | |-- values-v11/ 99 | | |--styles.xml 100 | |-- values-v14 101 | |--styles.xml 102 | 虽然libs目录和build.gradle和相关构建文件还在它原来的位置,其它的都变了。 103 | 104 | 在新的项目结构中,src/是源代码集的根目录,不仅仅是存放源代码的地方。有一个叫作“main”的源集在src/main目录中。在这个目录中,有assets/和res/目录以及AndroidManifest.xml文件。并且呢,有一个包含了了java源代码树的java/目录(本来放在原来的src/目录中)。 105 | 106 | ####build.gradle文件 107 | build.gradle文件就跟我们在Gradle介绍那一章描述的很像: 108 | 109 | buildscript{ 110 | repositories{ 111 | mavenCentral() 112 | } 113 | dependencies{ 114 | classpath 'com.android.tools.build:gradle:1.0.0' 115 | } 116 | } 117 | 118 | apply plugin: 'com.android.application' 119 | 120 | dependencies{ 121 | } 122 | 123 | android{ 124 | compileSdkVersion 19 125 | buildToolsVersion "21.1.2" 126 | } 127 | 128 | 我们有来描述我们构建工具所需的buildscript闭包,com.android.application插件。我们所编译的android版本以及使用的构建工具版本。 129 | 130 | 作为结果呢,我们有了标准的任务,包括installDebug. 131 | -------------------------------------------------------------------------------- /GradleandtheNewProjectStructure/WokingwiththeNewProjectStructureinAndroidStudio.md: -------------------------------------------------------------------------------- 1 | ###使用AndroidStudio中的新项目结构 2 | 3 | 毫不奇怪,Android Studio有着一些为了帮助你使用多种源集而设计的属性可供你创建和使用。 4 | 5 | ####构建变种视图 6 | 当我们运行我们的项目的时候,AndroidStudio并没有提示我们构建类型或产品风格。它只是运行而已。这就让我们产生疑问Android Studio是如何决定要运行哪个构建变种的。 7 | 8 | 这是由构建变种视图处理的,通常位于AndroidStudio集成开发环境窗口的左侧。 9 | 10 | 应用的每个模块都展示在这里,在你运行这个模块的时候,模块连同当前的构建变种类型就会被使用。 在构建变种上点一下会让你选择一个可替换的构建变种: 11 | 12 | ####Android项目视图 13 | 在这本书的早前内容中,当介绍AndroidStudio的时候,我们看到了Android项目视图。在别处,我们看到了Android项目视图是如何帮助你管理跨越多个资源集的资源的。 14 | 15 | 就像Android项目视图折叠资源集一样,它也能折叠源集: 这里呢,我们有两个版本的com.commonsware.myapplication 包。一个仅仅是包名,与此同时另一个有附加的“androidTest”。这就像你能想到的,分别反映出main和androidTest两个源集: 16 | 17 | 这在main和android之间可能有一点用。如果你实现了产品风格的话,就非常有用了。因为对应风格的类会并肩出现,至少是构建变种视图中当前选择风格。当前,AndroidStudio只把活跃的构建变种的源集(外加main和androidTest)当作是“源”,其它的构建变种源集仅仅被当做普通文件。 -------------------------------------------------------------------------------- /InternetAccess/HTTPviaDownloadManager.md: -------------------------------------------------------------------------------- 1 | ###通过DownloadManager的HTTP 2 | 3 | 如果你的目标是下载一些大文件的话,你可能最好使用在Android2.3添加的DownloadManager,因为它帮你处理了很多的底层的复杂性。例如,你开始在WIFI条件下下载,当用户离开房间设备就连接到了某种类型的移动数据,你需要重新连接到服务器,你要么重新下载,要么使用一些内容协商进行断点重连。DownloadManager进行的就是这个处理。 4 | 5 | 但是,DownloadManager是依赖于一些广播Intent对象的,这是一项我们还没讨论到的技术,所以我们会延迟在这[本书之后的内容]()涵盖DownloadedManager。 6 | 7 | -------------------------------------------------------------------------------- /InternetAccess/README.md: -------------------------------------------------------------------------------- 1 | ##网络访问 2 | 期待的是绝大部分Android设备有着内置的访问访问。它们可能是WIFI,蜂窝数据服务(EDGE,3G等等),或者可能完全其它的东西。 3 | 无论如何,大都数人,或者至少那些有着流量套餐或WIFI访问的人来说,他们可以通过他们的Android手机上网。 4 | 5 | 不令人惊讶的是,Android平台给予开发者较大范围的使用网络访问的方式。一些提供高级的访问,例如在[早前章节](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/TheWebViewWidget)中看到的集成WebKit浏览器组件(WebView)。 6 | 如果你想的话,你可以抛掉所有方式转而使用未加工的socket。或者,处于两者之间,你可以记住API-来自设备和第三方包的-它们让你能问特定的协议: 7 | HTTP,XMPP,SMTP等等。 8 | 9 | 这本书的重点在于高级形式的访问,[WebKit组件](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/TheWebViewWidget)和网络访问API,因为任何时候忙碌的编程人员应该尝试重用已存在的组件而不是在启动自己的线上协议。 10 | 11 | 目录: 12 | 13 | [`DIY HTTP`](/InternetAccess/DIYHTTP.md) 14 | [`HttpClient`怎么样](/InternetAccess/WhatAboutHttpClient?.md) 15 | [经由`DownloadManager`的HTTP](/InternetAccess/HTTPviaDownloadManager.md) 16 | [使用第三方JAR包](/InternetAccess/UsingThird-PartyJARs.md) 17 | [SSL](/InternetAccess/SSL.md) 18 | [使用HttpClient类库](/InternetAccess/UsingHTTPClientLibraries.md) 19 | [造访小径](/InternetAccess/VisittheTrails.md) 20 | -------------------------------------------------------------------------------- /InternetAccess/SSL.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/InternetAccess/SSL.md -------------------------------------------------------------------------------- /InternetAccess/UsingThird-PartyJARs.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/InternetAccess/UsingThird-PartyJARs.md -------------------------------------------------------------------------------- /InternetAccess/VisittheTrails.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/InternetAccess/VisittheTrails.md -------------------------------------------------------------------------------- /InternetAccess/WhatAboutHttpClient?.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/d83ed5c63379521a77b0ddbfbbe632263a3ef9d6/InternetAccess/WhatAboutHttpClient?.md -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/ExaminingtheGradleFiles.md: -------------------------------------------------------------------------------- 1 | ###分析Gradle文件 2 | 一个AndoridStudio项目可能有两个build.gradle文件,一个是项目层面的一个是模块层面的(例如在,app/目录)。对于单模块项目来说分开是不需要的-只需要一个build.gradle文件就可以了。 3 | 4 | 不管你的build.gradle文件是在一个地方,你还是能找到一些功能元素的。这节会对其进行概述。 5 | 6 | ####构建脚本 7 | Gralde中的构建脚本闭包(即,包含在括号中的代码块)是你配置JAR包和Gradle用来解释其它文件的地方。因此,你在配置构建脚本的时候你没有对项目进行配置。 8 | 9 | 10 | buildscript{ 11 | repositories{ 12 | mavenCentral 13 | } 14 | dependencies{ 15 | class 'com.android.tools.build.gralde.1.0.0' 16 | } 17 | } 18 | 19 | 构建脚本中的仓库闭包指示了依赖的来源,通常是Maven样式的仓库。这里的话,mavenCenteal()是一个内置的来设置Maven中心仓库信息的内置方法,一个流行的获取开源依赖的地方。 20 | 21 | 依赖闭包指示了要运行其余构建脚本需要的东西。classpath'com.android.tools.build:gradle:1.0.0‘,Gradle小组的文档不是很好。但是'com.android.tools.build:gradle:1.0.0'部分意味着: 22 | 23 | 在仓库中找到com.android.tools.build的手工品组 24 | 找到组内的gradle手工品 25 | 确保我们的是手工品的1.0.0版 26 | 当你首次运行你的构建的时候,有着如上所示的构建脚本闭包,Gradle会提醒你没有这个依赖。它会访问MavenCentral并且找到com.android.tools.build组以及组内的gradle的手工品,然后下载1.0.0版本。 27 | 28 | 有时候,版本的最后部分被一个加号符号所替代。这就告诉Gradle下载最新版本,从而自动升级到最新的补丁等级。(例如,某个时间点的1.0.3) 29 | 30 | ####应用插件 31 | com.android.tools.build:gradle:1.0.0依赖包含了一个GradleAndroid插件的依赖,教导Gradle Android特有的结构,例如会在这章之后涵盖到的android闭包里发现的内容。但是,仅仅下载依赖并没有应用任何东西。 32 | 33 | apply plugin:’com.android.application'声明真正为Grale构建添加了Android插件。尤其,指示了我们构建了一个Android应用。 34 | 35 | ####依赖 36 | 构建脚本中依赖闭包详述了构建脚本的依赖。build.gradle文件的根中的依赖闭包,对比而言,详述了应用的依赖。 37 | 38 | 但是,“依赖”的定义大都是相同的:它是一些我们需要添加到我们项目源代码中的类库或相似的手工品。 39 | 40 | 我们将在这本书之后的内容了解这些类库的概念。 41 | 42 | ####android 43 | android闭包包含了所有Android特有的配置信息。这个闭包是Android插件提供的。 44 | 45 | 但是在我们了解这个闭包里面有什么之前,我们应该改变下主题并讨论下manifest文件,因为android闭包中的内容和manifest中的内容有关。 46 | 47 | -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/GradleEnvironmentVariables.md: -------------------------------------------------------------------------------- 1 | ###Gradle环境变量 2 | 如果你自己安装了Gradle,你会要定义一个GRADLE_HOME环境变量,指向你安装Gradle的地方。并且添加Gradle的bin/目录到PATH环境变量。 3 | 4 | 你可能也会考虑设置一个GRADLE_USER_HOME环境变量,指向一个Gradle能创建.gradle子目录的目录,对于存放用户缓存和相关材料。默认情况,Gradle会使用你的标准home目录。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/GradleTheBigQuestions.md: -------------------------------------------------------------------------------- 1 | ###Gradle:大问题 2 | 首先让我们通过一系列常见问题解答调查这是关于什么的方式来打好基础。 3 | 4 | ####什么是Gradle? 5 | Gradle是用来构建软件的软件,也叫做“构建自动化软件”或“构建系统”。你可能在之前在其它环境中使用过其它构建系统,例如make(C/C++),rake(Ruby),Ant(Java),Maven(Java),等等。 6 | 7 | 这些工具,通过内在能力和你所教给它们的规则-如何决定什么是创建需要的(例如,基于文件改变)以及如何创建它们。一个构建系统并不直接编译,链接,打包应用。而是分成多个编译,链接,打包去做这个工作。 8 | 9 | Gradle使用基于Groovy的领域特定语言完成这些任务。 10 | 11 | ####什么是Groovy 12 | 有很多编程语言是设计成运行在Java虚拟机上的。它们中的一些,像JRuby和Jython,是实现了其它常见的编程语言(分别实现了Ruby和Python)。其它语言的就比较独特,而Groovy就是其一。 13 | 14 | Groovy脚本有点像Java和ruby的糅合体。如同Java一样,Groovy支持: 15 | 16 | 使用class关键字定义类 17 | 使用extends创建子类 18 | 使用import从外部jar包导入类 19 | 使用括号({和})定义方法 20 | 通过new操作符创建对象 21 | 如同Ruby一样,虽然: 22 | 23 | 声明可以作为类的一部分,或者仅仅以命令式风格,就像脚本语言 24 | 参数和局部变量不是强类型的 25 | 值可以自动拼接成字符串,虽然使用的是稍微有点不同的表达式(Groovy使用“Hello,$name”而Ruby使用“Hello,#{name}”) 26 | Groovy是一门解释性语言,像Ruby而不像Java。Groovy脚本是通过执行groovy命令运行的,传递给它要运行的脚本。Groovy运行时,尽管是一个Jar包,为了操作则需要JVM。 27 | 28 | 一个Groovy的优点是创建了DSL.例如,Gradle就是一个用来进行软件构建的Groovy DSL。Gradle特有功能似乎有一级语言构造,通常和功能本质难以区分开来。还有,Groovy DSL是大量陈述式的,像XML文件。 29 | 30 | 从某种程度上说,我们的到了两者的最好的地方:XML形式的定义(通常是更少的标点),还有着延伸到Groovy的能力并在有需要的情况下进行自定义脚本。 31 | 32 | ####什么是Android必须对Gralde做的事情 33 | Google发布了Gradle的Android插件,它给予了Gradle构建Andorid项目的能力。Google也使用Gradle和Android版Gradle作为AndoridStudio的构建系统。 34 | 35 | ####为什么我们要迁移到Gradle? 36 | 最初的时候,当我们要构建一个应用的时候,这些构建步骤是使用Eclipse和Ant完成的。Eclipse是集成开发环境,但Ant是命令行工具。Eclipse不使用Ant进行Andorid项目构建,而是有着它自己的构建系统。并且我们使用这些工具成功构建了百万以上的应用。这些工具仍然有用,虽然Ant支持正在衰退。 37 | 38 | 所以,为什么要改呢? 39 | 40 | 似乎有几个成因,包括: 41 | 42 | 维护两个独立的构建系统(Ant和Eclipse的本地尝试)变得耗时,并且会因AndroidStudio和其它构建系统的到来变得更糟。因此,Google想要基于Gradle,为IDE和命令行标准化一个单独的构建系统 43 | 44 | 用Ant脚本构建去做Google构建所需的每件事有点力不从心。 45 | 46 | Ant没有提供对“外部手工品”(例如,类库)很好的支持以及对这些类库的依赖管理。但是有着把Maven移植到Ant,或使用Maven自己的构建系统的方法,Google从不赞同这种尝试。在这一方面,Gradle提供了比Eclipse或Ant好得多的支持。并且使开发者放心使用来自多种多样作者的类库。 47 | 48 | Gradle设计成以类库的形式集成到IDE,远比Ant集成度高。 49 | 至于为什么Google选择Gradle而不是Maven...你就要问Google了。 50 | 51 | ####Gradle和AndroidStudio的关系? 52 | 如上所述,AndroidStudio使用新的基于Gradle的构建系统作为它构建Android项目的本地尝试。但是作为AndroidStudio核心的IntelliJ IDE也有着它自己的构建系统(就像Eclipse有一个一样),IDEA更易更换构建系统。 53 | 54 | 随着时间的推移,这允许Google专注于支持所有情形的单个构建系统(Gradle),而不是不得不去处理独立构建系统的集合。 55 | 56 | ####Gradle和Eclipse的关系? 57 | 写这本书的时候,Eclipse为Android构建脚本使用Gralde的能力,不管是直接还是座位项目源代码的配置数据导入。Eclipse的ADT插件有着导出项目Gradle构建文件的能力。 58 | 59 | Eclipse得到Gradle何种程度的支持是不知道的。最好假设不会在短时间内到来。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/IntroducingtheManifest.md: -------------------------------------------------------------------------------- 1 | ###介绍Manifest 2 | 任何Android应用的地基都是manifest文件:AndroidManifest.xml。这个文件会在Eclipse项目的根目录以及传统AndroidStudio项目app模块的src/main/目录中。 3 | 4 | 这是你声明什么在你应用中的地方-活动,服务等等。你也能指示这些部分是如何附加到整个Android系统的,例如,你能指示哪个活动(或多个活动)应该出现在设备的主菜单(又叫做,启动页) 5 | 6 | 当你创建你的应用的时候,你会得到一个为你生成的初始manifest。对于一个简单的应用,除单个活动之外没有其他东西,自动生成的manifest可能就能很好完成工作,或者可能需要较小的修改。另一方面,Android API 示例的的manifest文件长达1000行。你的Andorid应用产品可能会落在中间的某处。 7 | 8 | 就像之前提到的,一些项即可以在manifest也可以在build.gradle文件中定义。把东西放进manifest的方式仍旧可行,并且对Eclipse来说是唯一的方式,因为Eclipse并不搜寻build.gradle文件。对于AndroidStudio用户来说,你可能会使用Gradle文件并不会把这些共同元素定义在manifest中。 9 | 10 | -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/LearningMoreAboutGradlle.md: -------------------------------------------------------------------------------- 1 | ###学习更多关于Gradle的事情 2 | 3 | 这本书会深入研究Gradle,在核心章节和小径里都会有。但是,关注点会在用于Android的Gradle上,并且Gradle本身会比它提供更多。Gradle网站有着文档,Gradle相关的书籍,其它Gradle教育资源的链接。 4 | 5 | 目前,给Android的Gradle文档是有限的并且大都数都在android工具站点。需要注意的是关于新构建系统的首页以及Gradle插件用户指导,虽然跟实际工具相比可能会过时。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/ObtainingGradle.md: -------------------------------------------------------------------------------- 1 | ###获取Gradle 2 | 跟许多构建系统一样,要使用它,你需要构建系统的引擎。 3 | 4 | 如果你只会在AndroidStudio中使用Gradle,集成开发环境会为你处理好Gradle。但是如果你计划在AndroidStudio之外使用Gralde的话。(例如:命令行构建),你要考虑你的Gradle来自哪了。这对 于没有集成开发环境构建应用是很重要的,例如使用持续集成服务,像Jenkins这样的。 5 | 6 | ####直接安装 7 | 大都数开发者要想在AndroidStudio之外使用Gradle的最终都要直接安装Gradle。 8 | 9 | Gradle下载页包含了Gradle的zip压缩包:二进制文件,源代码,或者两者 10 | 11 | 你可以解压压缩包到你开发机上你要放的位置。 12 | 13 | ####Linux包 14 | 你可能通过linux环境中的包管理器获取Gradle。例如,就有一个Gradle的UbuntuPPA。 15 | 16 | ####gradle Wrapper 17 | 如果你是从其它人发布的项目开始的,你可能在项目根目录发现gradlew和gradlew.bat文件,以及一个gradle目录。这代表了"Gradle Wrapper"。 18 | 19 | GradleWrapper由三部分组成: * 批处理文件(gradlew.bat)和shell脚本(gradlew) * 批处理文件和shell脚本所使用的jar包(在gradle/wrapper/目录里) * gradle-wrapper.properties文件(也在gradle/wrapper/目录里) 20 | 21 | AndroidStudio使用gradle-wrapper.properties文件,从文件中的distributionUrl属性来决定去哪下载用于你项目的Gradle: 22 | 23 | 24 | distributionBase=GRADLE_USER_HOME 25 | distributionPath=wrapper/dists 26 | zipstoreBase=GRADLE_USER_HOME 27 | zipStorePath=wrapper/dists 28 | distributionUrl=https\://services.gradle.org/distributions/ gradle-2.2.1-1ll.zip 29 | 30 | 当你创建或导入一个项目的时候,或者你改变配置文件所引用的Gradle版本的时候,AndroidStudio会下载distributionUrl所指向的Gradle并安装它到你项目的.gradle/目录下。这个Gradle的版本就是AndroidStudio使用的。 31 | 32 | ####规则#1:只使用你相信的发布URL 33 | 如果你从第三方导入一个Android项目,例如这本书的例子-并且它们包含了gradle/wrapper/gradle-wrapper.properties文件,检查下发布url指向哪里。如果它是从service.gradle.org或者来自一个企业内部服务器,它可能是可信的。如果它指向位于其它地方的url,你要考虑性爱你是否真的要使用这个Gradle版本,因为它可能已经被篡改了。 34 | 35 | 这的批处理文件,shell脚本和jar包是为了支持命令行构建的。如果你使用gradlew,它会使用一个本地安装在项目.gradle目录的的Gradle拷贝。如果没有Gradle拷贝的话,像AndroidStudio一样gradlew会从发布URL下载Gradle。注意AndroidStudio并没有使用gradlew这套规则-它的逻辑是内置进AndroidStudio的。 36 | 37 | ####规则#2:只使用你真正相信的gradlew 38 | 检查一个.properties文件的检查URL是否合法是相对简单的。弄清楚批处理文件和shell脚本就有点不方便了。反编译jar包并弄清楚它就相对困难了。还有,如果你使用了来自某人的gradlew,在Gradle拷贝安装之后,脚本和Jar包是运行在你的开发机器上的。如果代码被篡改了,恶意软件有着你的开发机器和它所能触及的东西完整权限,例如你组织内的服务器。 39 | 40 | 注意你完全不需要使用GradleWrapper。如果你想要担心这个,在你的开发机器上安装一个Gradle版本并移除GradleWrapper文件。你可以使用gradle命令去构建你的应用(如果Gradle的bin/目录在你的PATH中),并且AndroidStudio会使用你的Gradle安装(如果你教导它去哪找,例如通过GRADLE_HOME环境变量)。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/OtherGradleItemsofNote.md: -------------------------------------------------------------------------------- 1 | ###其它需要注意的Gradle事项 2 | 3 | 在android闭包中你直接至少有两个声明:compileSdkVersion和buildToolsVersion. 4 | 5 | android{ 6 | compileSdkVersion 19 7 | buildToolsVersion "21.1.2" 8 | } 9 | 10 | compileSdkVersion定义了编译的API等级,通常是简单的API等级整数(例如,19)。一个Eclipse项目则会把这个放在项目根目录的project.properoties文件中。 11 | 12 | buidlToolsVersion指示了想要项目使用的AndroidSDK构建工具的版本。当从Maven中心下载的时候给了我们部分所需的,但不是完整的。其余部分来自SDK管理器的"AndroidSDK构建工具"入口。 13 | 14 | 意sdk管理器会允许你下载最新版本的Gradle构建工具(如上截图是20)以及之前的版本(例如.如上截图是18.0.1和17)。这和你的build.gradle文件中的buildToolsVersion相对应。 15 | 16 | 所以,你的android闭包会看起来像这样: 17 | android{ 18 | compileSdkVersion 19 19 | buildToolsVersion "20.0.0" 20 | defaultConfig{ 21 | applicationId "com.commonsware.empulite" 22 | versioncode 1 23 | versionName "1.0" 24 | minSdkVersion 15 25 | targetSdkVersion 18 26 | } 27 | } 28 | 29 | Eclipse并没有课配置构建工具版本概念,所以在一个Eclipse项目中就没有类似buildToolsVersion的东西。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/README.md: -------------------------------------------------------------------------------- 1 | ##介绍Gradle和Manifest 2 | 在AndroidStudio的讨论中,这本书提及到了叫作"Gradle"的东西,却没有大量的解释。 3 | 4 | 在这章中,我们将揭开Gradle的神秘面纱。 5 | 6 | (好吧,是其中的一些....) 7 | 8 | 我们也顺便提及了之前章节的“manifest”概念,它是作为我们Android项目的一个特殊文件。 9 | 10 | 一方面,Gradle和manifest不是强制关联的。另一方面,对于AndroidStudio 用户来说,一些(但离全部还很远)在manifest能设置的可以在Gradle中被覆盖。因为Eclipse用户不使用Gradle,它们的定义将永远在manifest它本身中。 11 | 12 | 所以,在这章中,我们会回顾什么是Gralde,什么是manifest,以及它们的规则,以及它们如何共同使用的基础。 13 | 14 | -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/TheRestOftheManifest.md: -------------------------------------------------------------------------------- 1 | ###Manifest的剩余部分 2 | 不是每个manifest都可以在Gradle构建文件中重写。这里就有一些只会出现在mainfest中的关键项,不管是以AndroidStudio,Eclipse还是其它方式创建的. 3 | 4 | ####给应用的Application标签 5 | 在你的初始项目manifest中,元素的主要子元素是一个元素。 6 | 7 | 默认时,当你创建一个新的Android项目,你得到了处于中的单个元素: 8 | 9 | 10 | 11 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 这个元素为实现活动的类提供了android:name,为活动名的展示提供了android:label,并且有时候提供一个这个子元素来描述在什么条件下活动会被展示出来。常备的元素吧你的活动设置成启动页,所以用户可以选择运行它。正如我们将在之后这本书所看到的,如果你要选的话,你可以在一个项目中有许多个活动。 28 | 29 | 在此例中的android:name 属性,有一个光秃秃的Java类名(Now).有时候,你可以看到有着完全合格类命的android:name(例如,com.commonsware.android.skeleton.Now)。有时候,你会看到有着单个句号前缀的类命。Now和.Now都指向在你的项目包(你声明在中的package属性)中的Java类。 30 | 31 | 支持多样的屏幕 32 | Android设置有着宽阔的屏幕范围,从2.0寸的小型智能手机到46寸的电视机。Android基于物理尺寸和通常间隔把这些分成四个桶: 33 | 34 | 1.小(3寸以下) 35 | 36 | 2.常规(3寸到4.5寸) 37 | 38 | 3.大(4.5寸到10寸) 39 | 40 | 4.超大(10寸以上) 41 | 42 | 默认情况下,你的应用会支持小的和常规的屏幕。它也会通过一些Android的自动转化进而支持大屏和超大屏。 43 | 44 | 为了真正支持所有你要的屏幕尺寸,你应该考虑在你的manifest中添加元素。这个例举了你已经明确支持的屏幕尺寸。例如,你为大屏和或超大屏提供自定义UI支持,你将会需要元素。所以,虽然初始的manifest能工作,处理多屏幕尺寸是你要考虑的问题。 45 | 46 | 即一个元素类似于: 47 | 48 | 11 | 12 | 注意android命名空间声明。你只能在许多属性上使用命名空间而不是元素上(例如,而不是) 13 | 14 | 你需要提供给文件的信息的最大部分是包名属性。 15 | 16 | 包名属性一直都需要在manifest中,即使对AndroidStudio项目来说。包名属性会控制一些源代码在哪为我们生成,尤其是我们会在稍后遇到的一些R和BuildConfig类。 17 | 18 | 因为包名是用于生成Java代码的,它必须是合法的Java包名。java习惯包名应该基于一个颠倒的域名(例如,com.commonware.empulite),讨论的是你的域名。这样的话,重名就不太可能了。 19 | 20 | 包名也作为我们应用的默认"应用标识"。这需要一个唯一的标识,例如: 同一设备同一时间不能安装相同应用标识的两个应用 21 | 相同应用标识的两个应用不能上传到Google应用市场 22 | 默认情况,应用ID就是包名,但是AndroidStudio用户可以在他们的Gradle构建文件中进行覆盖。特别的,在android闭包中可以是默认配置闭包,并且在其中可以有一个applicationId声明: 23 | 24 | 25 | android{ 26 | //other stuff 27 | defaultConfig{ 28 | applicationId "com.commonsware.empulite" 29 | //more other stuff 30 | } 31 | } 32 | 33 | 不仅AndroidStudio用户可以在默认配置闭包中覆盖应用标识,也有不同情形性爱有着不同应用标识的方式,例如调试构建对比发布构建。我们会在本书之后稍后内容中进行探讨。 34 | 35 | ####minSdkVersion和targetSdkVersion 36 | 你的manifest可能也包含了一个作为元素子元素的元素,来指定你支持什么版本的Android。此外,它能包含andorid:minSdkVersion和android:targetSdkVersion属性。Eclipse项目会一直有这个属性。AndroidStudio项目可能没有这个属性,因为这些值也能在默认配置闭包(应用标识可以被定义的地方)中定义为minSdkVersion和targetSdkVersion属性。 37 | 38 | 两个之中,更为关键的是minSdkVersion。它指示了你所测试应用所用的最老版本的Android。属性的值是代码AndroidAPI等级的整数。所以,你只在Android4.1或以上测试你的设备,你应该把你的minSdkVersion设置成16。 39 | 40 | 你也可以指定一个targetSdkVersion。这指示了你些代码时所考虑的Android版本。如果你的应用是运行在一个较新版本的Android上,Android可能作一些事来提高你代码的兼容性于较新Android相适应。现如今,大都数Android开发者应该制定目标SDK版本为15或者更高。随着本书内容的深入我们会开始探索更多关于targetSdkVersion的东西,但这时候,不管你的集成开发环境给你的默认值是多少,都可能是好的开始。 41 | 42 | build.gradle中的对应条目就到默认配置闭包中了: 43 | 44 | 45 | android{ 46 | defaultConfig{ 47 | applicatinId "com.commonsware.empulite" 48 | minSdkVersion 15 49 | targetSdkVersion 19 50 | //more other stuff 51 | } 52 | } 53 | 54 | ####版本号和版本名 55 | 在根元素之上,你的manifest清单也可以定义android:versionName和android:verisonCode属性。即使如此,一个AndroidStudio项目经常跳过这些,并在默认配置闭包中通过versionName和versionCode属性进行设置。 56 | 57 | 这两个值代表了你应用的版本。versionName的值是用户会在它们的应用设置里的应用详情界面会看到的一个版本指示。 58 | 59 | 60 | 同时,版本名称也被google应用市场目录所使用,如果你按此中方式发布你的应用的话。版本名称可以是任何你想要的字符串值。 61 | 62 | 另一方面,版本号一定要是一个整数值,并且一个新的版本必须比旧的版本的高的版本号。Andorid和Google市场会比较新的APK和已安装应用的版本号来决定是否要更新APK。通常的做法是版本号从1开始,并且在每次发布的时候增加它。当然,你可以选择其它你想要的约束。在开发期间,你可以把这些放在一边,但是当你产品化的时候,这些属性就变得很重要了。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/VersionsofGradleandGradleforAndroid.md: -------------------------------------------------------------------------------- 1 | ###Gradle版本和用于Android的Gradle版本 2 | 3 | 我们会使用的会赋予Gradle“超级Andorid力量”的GradleAndroid插件是周期更新的。每个更新有着与之对应所需的Gradle版本。 4 | 5 | 据谷歌说,规则是: 6 | 7 | AndroidStudio 1.x能跟任意版本为1.x的GradleAndroid插件配合使用,"x"的值不用对应 8 | Gradle Android1.x应该能跟所有的Gradle2.x版本配合使用 9 | 如果你使用GradleWrapper,你使用的是项目安装在本地的Gradle。只要项目的Gradle版本和在build.gradle文件中GradleAndroid要求的版本匹配-就像在下一章中会涵盖的东西一样,状况就比较良好。 10 | 11 | 如果你不使用GradleWrapper,你将要需要决定什么时候获得一个新的Android Gradle 发布版本并更新你的Gralde安装和连接在一起的build.gradle文件。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/VisittheTrails.md: -------------------------------------------------------------------------------- 1 | ###造访小径 2 | 在这本书中有着一些更多的关于使用Gradle和给Android的Gradle的章节。 3 | 4 | * Gralde和历史项目是给在Eclipse样式项目上使用Gralde的开发者的 5 | * Gradle和任务解释了我们如何基于我们的行为(“任务”)来做一些事情,例如为我们编译我们的APK 6 | * Gradle和新的项目结构阐述了为什么项目结构不再是Eclipse使用的结构,作为结构我们获得了什么功能,包括配置“构建类型”和“产品特性”的能力。 7 | Gralde和依赖涵盖了在这章中早先提及到的“手工品”,只要通过build.gradle文件中的几行我们就可以把类库自动添加到我们的项目。 8 | 也有关于其它Gralde主题的"给Android的高级建议"章节,以及Gradle的清单合并章节。 -------------------------------------------------------------------------------- /IntroducingGradleandTheManifest/Where'sTheGUI.md: -------------------------------------------------------------------------------- 1 | ###图形界面在哪 2 | 你可能在疑惑为什么我们必须吃力地在这些Groovy代码中穿梭并且疑惑是否一些图形界面能影响Gradle设置的. 3 | 4 | 答案是有也可以是没有。 5 | 6 | 有个项目结构对话框,允许你的维护这些东西的一些。但是,随着构建程度越来越复杂,GUI就越不可能满足,并且你需要更多直接使用Gradle构建文件。因此,这本书倾向于专注于构建文件。 7 | 8 | -------------------------------------------------------------------------------- /JUnitandAndroid/README.md: -------------------------------------------------------------------------------- 1 | ##JUnit和Android 2 | 3 | 除了你自己仅仅手动去做之外,你可能会要测试你的代码。Android提供了一些测试你的app的方法,涵盖在接下来的一系列章回中。 4 | 5 | 第一个我们会分析的Android SDK测试解决方案是JUnit测试框架。这是一个标准的Java单元测试框架。Android SDK装载了一个版本的JUnit,以及特定的测试类来帮助你构建运行像活动和服务这样的Android组件。 6 | 7 | -------------------------------------------------------------------------------- /KeyAndroidConcepts/AndroidApplications.md: -------------------------------------------------------------------------------- 1 | ###Android应用程序 2 | 3 | 这本书关注于写Android应用程序。应用程序是用户从应用商店或其它地方下载到它们设备可能会进行安装的一个东西。 4 | 应用程序应该有一些用户界面,并且它可能有其它设计成在后台运行的代码(多任务)。 5 | 6 | 这本书不关注Android硬件的修改,例如写硬件驱动。要是这样的话,你应该搜寻其它资源。 7 | 8 | 这本书假定你有一些关于Android设备的实战经验,因此你要熟悉主界面和返回按钮,内置的设置应用,主界面和启动器的概念等待。如果你从来没有使用过Android设备的话,强烈建议你买一个(例如...在闲鱼、淘宝等上买个二手的),并在学习Android应用开发之前在花点时间熟悉它。 9 | 10 | ####编程语言 11 | 12 | 大多数的Android应用都是用纯JAVA代码写的。因此,这本书花费了大量的时间在这上面并用大量的例子来进行示范。 13 | 14 | 但是,也有其它选择: 15 | 16 | * 你可以将应用的部分用C/C++编写,来获取性能提升,移植已有的代码库等待。 17 | * 你可以将应用全部用C/C++编写,主要是为了使用OpenGL3D动画。 18 | * 你可以用HTML,CSS,和JavaScript作为应用的内核,使用工具把这些材料打包进Android应用中,可以通过Google市场和其他类似的应用市场进行发布。 19 | * 等等 20 | 21 | 这些非Java的替代方案会在这本书的小径中找到,因为这本书的大部分是关注Java的。 作者假定你这时候已经知道Java了。如果你不知道,你需要在走更远之前你需要学习下Java。你不需要知道JAVA的每一件事,因为Java的范围是巨大的。因此,聚焦于: 22 | 23 | * 语言基础(流程控制,等等) 24 | * 类和对象 25 | * 方法和成员变量 26 | * 公共、私有和保护 27 | * 静态和实例作用域 28 | * 异常 29 | * 线程 30 | * 集合 31 | * 泛型 32 | * 文件输入输出 33 | * 反射 34 | * 接口 35 | 36 | 这些主题链接到维基教科书,尽管有无数java资源供你选择。 37 | 38 | ####组件 39 | 40 | 你首次学习java的时候,不管是昨天还是很久之前,你可能从像这样的东西开始: 41 | 42 | class SillyApp{ 43 | public static void main(String[] args){ 44 | System.out.println("Hello world!") 45 | } 46 | } 47 | 48 | 换句话说,你的应用入口是一个叫作main()公共的静态void方法,这个方法把字符串数组作为参数。从那起,你负责做任何必要的事情。 49 | 50 | 但是,在java中有被使用在其它地方的模式。例如,当你写一个Java servlet的时候,你通常不用写main()方法。作为代替,你继承了一个由框架提供的特定类(例如,HttpServlet)来创建组件,然后写了一些元数据来列举你的组件并告诉框架何时以及如何使用它们。(例如,web.xml) 51 | 52 | Android应用和Servlet的方式是神似的。你不会要写一个公共的静态void方法。作为替代,你将创建一些由Android提供的定义了多种应用组件的基类的子类。此外,你要创建一些元数据把这些子类告诉Android。 53 | 54 | #####活动 55 | 56 | 用户界面的构件是活动。你可以把Android的活动想成桌面应用上的窗口或对话框,或者是网页应用中的页面。它表现了你用户界面的大部分,在一些情况下,是你的应用中一个互无关联的入口。(这就是说,其它应用链接到你的应用的方式)。 57 | 58 | 通常,活动会占据屏幕的大部分,给一些像时钟、信号强度等等的色块留下空间。 59 | 60 | #####服务 61 | 62 | 活动是短命的并且可能在任何时间被关闭,例如用户按下返回按钮的时候。服务,从另一个角度说,是被设计成保持运行状态的,如果需要的话,在适度时间内是和所有活动独立开来的。你可能使用服务来检查对一个RSS订阅消息的更新,或者播放音乐即使控制活动已经不再操作了。你也可以用服务事项定时任务(类似于Linux或OSX的“cornjobs”)并把自定义API暴露给设备上的其它应用,尽管后者是相对高级的功能。 63 | 64 | #####内容提供者 65 | 66 | 内容提供者为存储在设备上的任意数据提供了一个抽象层,这个抽象层可以被多个应用访问。Android开发模型鼓励你让你的数据可以被自己和其他应用访问-创建一个内容提供者让你做到了这个,在你的数据如何获取访问上保持了一定程度的控制。 67 | 68 | #####广播接收者 69 | 70 | 系统或应用,会不时地发出广播,包括各个方面从电池快没电、到屏幕关闭、到连接从wify改为移动数据。 71 | 广播接收器能很好地安排这些广播并作出相应的响应。 72 | 73 | #####控件、容器、资源和碎片 74 | 75 | Android应用开发的大都数关注度是在UI层和活动上。大都数Android活动使用的名为“控件框架”来渲染它们的用户界面,尽管如此你使用2D(Canvas)和3D(OpenGL)来做更专业化的图形界面设计也是受欢迎的。 76 | 77 | 对Android而言,控件是用户界面的微单位。输入框、按钮、文本框、列表等待都是控件。你活动的用户界面,因此,是有一个或多个这些控件组成的。 78 | 例如这里我们看到了文本框、输入框和按钮控件: 79 | 80 | 如果你有着一个以上的控件-这是相当常见的-你需要告诉Android这些控件是如何在屏幕上组织的。为了完成这个,你会使用多种被称为布局管理器的容器类。它们会让你把东西按行、列或如果需要的话按更为复杂的组织方式进行排列。 81 | 82 | 为了描述容器和控件是如何关联的,你通常要创建一个布局资源文件。Android中的资源指的是像图片、字符串和其他你的应用使用的但不是以编程语言源代码形式的材料。用户界面布局是另一种零星的资源。你可以使用构造工具,例如集成开发环境的拖放图形界面创建者,或者以XML形式手写创建这些布局。 83 | 84 | 有时候,你的用户界面会在所有的设备:手机、平板、电视等等设备上使用。有时候,你的用户界面需要针对不同的环境进行修改。你能够把资源放进资源集中来指示这些资源是在什么条件下可以被使用的。(例如,这些在正常大小屏幕上使用,这些在大屏上使用) 85 | 86 | 随着对这本书的深入,我们将更加详细地分析这些概念。 87 | 88 | ####应用和包 89 | 90 | 给予一桶源代码和一篮子资源,Android编译工具会给你一个应用作为结果。应用是以APK文件形式给出的。它就是你要上传到谷歌市场或其它分发途径的APK文件。 91 | 92 | 每个Android应用都有一个报名,叫作应用标识。一个包名必须满足三个条件: 93 | 94 | 1.它必须是一个合法的java报名,因为一些java源代码大会通过Android编译工具生成在这个包中。 95 | 96 | 2.相同应用标识的应用不能再同一个设备上存在 97 | 98 | 3.相同应用标识的应用不能上传到谷歌市场 99 | 100 | 当你创建你的Android项目的时候,源代码和这些资源的库-你要声明你的应用使用的是什么包名。通常来说,你要选择一个遵循java包名“反向域名”惯例(例如:com.commonware.android.foo)。这样,域名系统保证了你的包名前缀是独一无二的,包名的其余部分如何对应用进行区分就由你决定了。 101 | -------------------------------------------------------------------------------- /KeyAndroidConcepts/AndroidDevices.md: -------------------------------------------------------------------------------- 1 | ###Android设备 2 | 3 | 今天有超过十亿的Andorid设备在使用,代表着成千上万个来自不同厂商的不同型号。Andorid自2008年的Android1.0之后不断进化。在不同设备类型和不同Android版本之间,许多媒体专家对Android的碎片化问题怨声载道,表明创建能运行在所有这些不同环境上的应用是不可能的。 4 | 5 | 实际上,没有那么糟糕。一些应用会有潜在的问题,但是大都数应用都能正常使用如果你遵循这本书和其他资源的指导。 6 | 7 | ####类型 8 | 9 | Android设备形状、大小和颜色各不相同。但是,有四种主要形态。 10 | 11 | * 手机 12 | * 平板 13 | * 电视 14 | * 穿戴式设备(智能手表,Google眼镜等等。) 15 | 16 | 你通常听到开发者和专家提及这些形态,并且这本书也会时不时这么做。但是,你要理解Android1没有内置的关于设备是手机或是平板或是电视的概念。反之,Android根据功能和特性区分设备。所以,你到处找不到一个isPhone()方法,尽管如此,你可以问Android: 17 | 18 | * 屏幕尺寸大小 19 | * 设备有电话功能吗? 20 | * 等等 21 | 22 | ####模拟器 23 | 24 | 自从2007年底beta版本发布之后,Android以及走了一段很长的路。Andorid每个新系统版本添加了更多的功能到平台上并且开发者能在这些功能上探索做更多的事情。 25 | 26 | 此外,Android核心开发组努力保证前后兼容。一个你今天写的应用应该能在将来版本的Andorid上(向前兼容),虽然可能缺少了一些属性或在某种兼容模式中。并且有用旧了的方法来创建能在最新和之前版本Android(向后兼容)上使用的应用。 27 | 28 | 为了帮助我们记录对我们开发者来说所有不同的操作系统版本,Android有API等级。新的API等级在Android版本包含了能影响开发者的改变的时候被定义。当你创建一个模拟器来测试你的应用的时候,你要指示模拟器模拟哪个API等级的模拟器。当你发布你的应用的时候,你要支持你的应用所支持的最老API等级,所以应用不能安装在更老的设备上。 29 | 30 | 正在写的时候,对大都数Andorid开发者来说重要的API等级有: 31 | 32 | * API等级16(Android 4.1) 33 | * API等级17(Andorid 4.2) 34 | * API等级19(Android 4.4) 35 | * API等级21(Android 5.0) 36 | * API等级22(Android 5.1) 37 | 38 | 在这里,重要是是指有很多数量Android设备-5%或者更多,根据平台版本仪表板图所报告的。 39 | 40 | 最新的API等级是23,代表Android 6.0。 41 | 42 | 注意被Android4.4运行在首代Android穿戴设备上的是API等级20。除非你要特别开发给穿戴设备的应用,否则你不需要担心API等级20太多。 43 | 44 | ####Dalvik 45 | 46 | 对Andorid而言,Dalvik是虚拟机。虚拟机被许多编程语言所使用,例如Java、Perl和Smalltalk。Dalvik虚拟设计成像Java虚拟机一样工作,但是对Linux环境进行了优化。 47 | 48 | 所以,当某人编写一个Andorid应用的时候发生了如下事情: 49 | 50 | 1.开发者编写java语法源代码,依赖Andorid项目和第三方的类库。 51 | 52 | 2.开发者使用JavaSDK提供的javac编译器把编译源代码成Java 虚拟机字节码。 53 | 54 | 3.开发者把Java虚拟机字节码转换成Dalvik虚拟机字节码。Dalvik虚拟机字节码和其它文件一起打包进一个以apk为扩展名的ZIP压缩文件。 55 | 56 | 4.Android设备或模拟器运行APK文件,使字节码在Dalvik虚拟机实例上执行。 57 | 58 | 从你的视角看,这些东西中的大都数都被开发工具所隐藏了。你从顶端注入Java源代码,APK文件从底部出来。 59 | 60 | 但是,Dalvik虚拟机和传统Java虚拟机不同的地方会时不时影响应用开发者,并且会在相关的地方指出来 61 | 62 | 注意Android正迁移到一个新的叫作ART的运行时环境。但是,Dalivik术语仍会在被用做作构建应用的字节码上使用。 63 | 64 | 65 | ####进程和线程 66 | 67 | 当你的应用运行的时候,它会运行在它的进程里。这跟其他传统的操作系统没有明显区别。部分Dalvik的神奇之处是让多个进程能运行多个Android应用而不是消耗荒谬数量的RAM。 68 | 69 | Android也会安排一批线程来运行你的应用。你的代码大部分时间运行在的线程,可以叫作主应用线程或用户界面线程。你不需要设置它,但在这本书的稍后内容中,你会需要关注什么能在主线程什么不能再主线程上做。你也欢迎分叉你自己的线程来完成工作,并且这是相当常见的,尽管在一些地方Android在幕后为了进行了处理。 70 | 71 | -------------------------------------------------------------------------------- /KeyAndroidConcepts/Don'tBeScared.md: -------------------------------------------------------------------------------- 1 | ###不要害怕 2 | 3 | 对,这章扔给你大量的术语。我们会在这本书中更详细地学习它们所有的内容。但是,Android是由大量联锁块拼成的拼图。为了能仔细描述一个概念,你无论如何都需要引用其它内容。因此,这章的目的是让你知道你这些属于,希望在我们深入过程中它们会听起来很耳熟。 -------------------------------------------------------------------------------- /KeyAndroidConcepts/README.md: -------------------------------------------------------------------------------- 1 | ##关键Android概念 2 | 3 | 毫无疑问,你很着急想要开始Android应用开发。毕竟,你在看这本目标为忙碌程序员的书。 4 | 5 | 但是,在我们进入工具设置和开始实际开发之前,我们把关于Android的一些高级概念列到同一页上是很重要的。 6 | 这会使这本书中稍后的进一步讨论变得简明。 7 | 8 | 目录: 9 | 10 | * [Android应用程序](/KeyAndroidConcepts/AndroidApplications.md) 11 | * [Android设备](/KeyAndroidConcepts/AndroidDevices.md) 12 | * [不要害怕](/KeyAndroidConcepts/Don'tBeScared.md) 13 | -------------------------------------------------------------------------------- /MiscellaneousNetworkCapabilities/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 这章的读者应该已经读了这本书的核心章节。 -------------------------------------------------------------------------------- /MiscellaneousNetworkCapabilities/README.md: -------------------------------------------------------------------------------- 1 | ##多种多样的网络功能 2 | 这章是对多种与网络I/O和互联网相关的Android功能的全方位覆盖,没有提到的也在这本书的其它地方。 3 | -------------------------------------------------------------------------------- /Preface/AbouttheAPKEdition.md: -------------------------------------------------------------------------------- 1 | ###关于APK版 2 | 3 | 除了传统的电子书格式(PDF,EPUB,MOBI/Kindle)之外,这本书也有以APK文件形式获取的Android应用。 4 | 这个应用有着一个集成的电子阅读器,向你展示你能在这本书EPUB版本所能找到的相同内容。但是,它有着一些突出的特性。 5 | 6 | 首先,它有着一个内置的十分快速的全文本索引。你能够快速地搜索关键字,类名等等,在大都数Android硬件上都是次秒级响应的。 7 | 你甚至能够使用布尔搜索子句(例如,搜索encryption OR decryption)。 8 | 9 | 其次,它有一个社区剧院,你可以在其中看基于应用的训练单元。其中有演示文稿,完整的幻灯片,视频,屏幕录像和源代码等。 10 | 通过社区剧院,你可以浏览可用的教程,下载那些你感兴趣的,然后当你想看的时候就能看了。 11 | 12 | 这本书的APK版本能工作在Android 4.0.3以及更改的版本上,尽管 13 | 社区剧院部分只能工作在Android 4.4以及更高版本上。 14 | 15 | APK的安装说明书可以在CommonsWare站点上找到。关于使用社区剧院的细节可以在这本书的附录中找到。 16 | -------------------------------------------------------------------------------- /Preface/AbouttheUpdates.md: -------------------------------------------------------------------------------- 1 | ###关于更新 2 | 这本书的更新很频繁,通常每6-8个星期就更新一次。 3 | 4 | 每个发布版本有着表明什么是新的或跟前一个发布版相比的改变的标记: 5 | 6 | * 目录中用bold-italic字体来表明那些章节被修改过了 7 | * 这些右侧有更改条的章节意味着特定的章节是新的或被修改过 8 | -------------------------------------------------------------------------------- /Preface/Acknowledgment.md: -------------------------------------------------------------------------------- 1 | ###感谢 2 | 3 | 我想要感谢Android小组,不止因为拿出了一个很好的产品,也为在AndroidGoogleGroups和StackOverflow上无法估量的援助。 4 | 5 | 我也要感谢这本书过去版本数千读者,感谢他们的反馈、bug报告和整体支持。 6 | 7 | 当然,也要感谢整个Android生态系统,特别是那些贡献他们的技能到发布库、写博客、解答支持问题的人以及其它有助于Android的力量。 8 | 9 | 这本书中的部分内容是从Android开放源代码项目创建和贡献的工作复制来的并依照知识共享2.5归属许可进行使用 -------------------------------------------------------------------------------- /Preface/CC&42FG.md: -------------------------------------------------------------------------------- 1 | ###知识共享和42F保证 2 | 3 | 在知识共享非商业授权下,每本CommonsWare书在发行日期的四周年或卖出4000份二者之一条件满足的时候将可以使用。这意味着,一旦四年过去之后,你可以使用这本书用作非商业用途。这就是对我们读者和更广泛社区的42F保证。出于这个保证的目的,从这个版本发布开始,新的Waresciptions和更新都会进行计数统计。 4 | 5 | 根据上述只是共享许可这本书的这个版本将在2020年5月1号可用。当然,查看Commonware 网站,这个版本可能不久会因销量重新许可。 想要了解知识共享非商业授权,可以查看知识共享网站。 6 | 7 | 注意这本书的将来版本日后会将免费,这个版本发布后的每四年或者基于特定版本的销量。发布一个知识共享许可喜爱的版本不意味着发布许可证下的所有版本。 8 | -------------------------------------------------------------------------------- /Preface/ExendingYourWarescription.md: -------------------------------------------------------------------------------- 1 | ###延长你的Warescription 2 | 除了通过常规方式(例如,支付)延长你的Warescription之外,还有一些提供给订阅者能让 3 | 其Warescription再免费一段时间的项目。 4 | 5 | 6 | ####书中BUG奖励 7 | 发现了我们书中的一个问题?让我们知道! 8 | 9 | 作为第一个发现当前版本电子版本的一个突出的具体问题,我们会把你的Warescription延长6个月作为帮助我们生产更好产品的奖励。 10 | 11 | 具体问题,我们指的是这样的事情: 12 | 13 | 1.印刷错误 14 | 15 | 2.例子应用没有像说的那样可以在这本书描述的环境中工作。 16 | 17 | 3.不能被解释器打开的事实错误 18 | 19 | 独一无二,我们意味着那些没有被报告过的,确保在查看核心错误页之后,来查看你的问题是否已经被报告过了。每个包含合格bug报告的电子邮件都会给予一张优惠券。 20 | 21 | 我们也欣赏听到软件问题,例如: 22 | 23 | 那些你认为我们是错的而我们感觉我们的解释是合理的 24 | 25 | 那些你认为我们可以添加例子应用,或者在已存在的材料商进行扩展 26 | 27 | 因为底层环境不断变化而不能工作的例子(例如,新的SDK中更改的API) 28 | 29 | 但是,这些软件问题并不符合正式的奖励程序。 30 | 31 | 关于Bug奖励的问题,或那些你想报告为奖励考虑的问题,应该被发送bounty@commonsware.com -------------------------------------------------------------------------------- /Preface/README.md: -------------------------------------------------------------------------------- 1 | ##前言 2 | 3 | Android的世界很精彩 4 | 5 | Android的世界很无奈 6 | 7 | 当你觉得Android的世界很精彩 8 | 9 | 我会在这里衷心的祝福你 10 | 11 | -译者序 12 | -------------------------------------------------------------------------------- /Preface/SourceCodeandItsLicense.md: -------------------------------------------------------------------------------- 1 | ###源代码和它的许可证 2 | 3 | 这本书中展示的源代码例子可以在这本书的Github仓库获取。所有的Android项目都在Apache2.0许可证下,以备你想要重新使用它们中的任意一个。 4 | 5 | 如果你想要使用来自Gihub仓库的源代码,请依照仓库主页的说明来得知如何在多种开发环境中使用的细节,特别是Android Studio。 -------------------------------------------------------------------------------- /Preface/TheBook'sStructure.md: -------------------------------------------------------------------------------- 1 | ###这本书的结构 2 | 3 | 你可能已经注意到了,这是相当大规模的一本书。 4 | 5 | 为了能处理相当于3500页左右的内容材料,文章被分成了核心章回和一系列小径。 6 | 7 | 核心章回描述了许多Android开发者构建一个应用所需要理解的关键概念。但是偶尔例如会有个可有可无的主题 8 | 为了帮助阐释某个观点而穿插到核心章回中。所以核心章节通常是相当必要的。 9 | 10 | 核心章回是被设计成按顺序阅读的,并且会交织着传统技术文章和教程,在讨论概念的同时给予你实践经验。 11 | 大都数的教程都是可以被跳过的。尽管如此,涵盖设置SDK环境以及创建项目内容的头两章,是每个读者都应该进行阅读的。 12 | 13 | 大量的章回被分成了多个小径,其中涵盖到了某些具体一般性主题,从数据存储到高级UI效果到性能测定和调优。 14 | 每个小径都会有许多章回。但是,这些章回以及这些小径它们本身,是没有必要被设计成以任何顺序的形式进行阅读的。 15 | 小径中的每个章回会指出了你所需要提前了解的章回或概念。因此,这些章回大都是参考材料, 16 | 当你具体地想学习关于一个特定主题的一些东西的时候会用到。 17 | 18 | 核心章回会链接到多个小径中的多个章回,为了向你展示你从哪能能找到与你刚刚阅读到的东西相关的材料。 19 | 所以在这本书的目录,这份前言,你的电子阅读器中的搜索工具,以及跨章节链接之中, 20 | 你应该有了足够多的方式去发现你要阅读的材料。 21 | 22 | 如果你想的话你是可以从前到后阅读整本书的。多个小径会出现在核心章回之后。这些多个小径会以一个合理的逻辑顺序出现, 23 | 尽管如此,你可能为了做好所有的准备工作而不得不从章回之间跳来跳去。 24 | -------------------------------------------------------------------------------- /Preface/TheTrails.md: -------------------------------------------------------------------------------- 1 | ###那些小径 2 | 3 | 这里是一份以出场顺序排列所列出的所有小径的清单以及与这些小径相关的章回。(除了出现在列表中多次的小径之外,因为它们跨越了多个主要类别): 4 | 5 | ####代码组织和`Gradle` 6 | * [使用类库项目](/WorkingwithLibraryProjects/README.md) 7 | * [`Gradle`和旧式项目](/GradleandEclipseProjects/README.md) 8 | * [`Gradle`和`Tasks`](/GradleandTasks/README.md) 9 | * [`Gradle`和新项目结构](/GradleandtheNewProjectStructure/README.md) 10 | * `Gradle`和依赖 11 | * `Manifest`合并规则 12 | * 应用签名 13 | * 发行 14 | * 用于`Android`的高级`Gradle`小窍门 15 | 16 | ####测试 17 | * 使用`JUnit4`进行测试 18 | * 使用UIAutomator进行测试 19 | * 单元测试 20 | * `MonkeyRunner`和`Test Monkey` 21 | 22 | ####高级UI 23 | * 通知 24 | * 高级通知 25 | * 介绍GridLayout 26 | * 百分比支持库 27 | * `Dialog`和`DialogFragment` 28 | * 高级`ListView` 29 | * `Action Bar` 导航 30 | * `Action Modes`和`Context Menus` 31 | * 其它高级`Action Bar`技巧 32 | * `ToolBar` 33 | * `AppCompact`:官方`Action Bar`向后兼容 34 | * `RecyclerView` 35 | * 实现一个导航抽屉 36 | * `Android`设计支持库 37 | * `WebView`的高级使用 38 | * 输入法框架 39 | * 字体 40 | * 富文本 41 | * 动画 42 | * 旧式动画 43 | * 自定义`Drawables` 44 | * 使用`Maps V2`绘制地图 45 | * 手工制作你自己的视图 46 | * 高级`Preference` 47 | * 自定义对话框和`Preference` 48 | * 进度指示器 49 | * `Pagers`还有更多的乐趣 50 | * 关注管理和可访问性 51 | * 多种UI策略 52 | * 事件总线替代品 53 | * `Tasks` 54 | * 助手API 55 | * 数据绑定 56 | * 桌面`Android`应用 57 | 58 | ####主页面效果 59 | * 主页面控件 60 | * 基于适配器的应用控件 61 | 62 | ####数据存储和检索 63 | * 内容提供者理论 64 | * 内容提供者实现模式 65 | * 加载框架 66 | * `ContactsContract`提供者 67 | * `CelendarContract`提供者 68 | * `MediaStore`提供者 69 | * 使用文档 70 | * 提供文档 71 | * 加密存储 72 | * 打包和分发数据 73 | * 高级数据库技巧 74 | * 数据备份 75 | 76 | ####高级网络主题 77 | * SSL 78 | * 嵌入网站服务 79 | * 多种多样的网络功能 80 | 81 | ####`Media` 82 | 83 | * 音频播放 84 | * 音频录制 85 | * 视频播放 86 | * 通过第三方应用使用相机 87 | * 直接使用相机 88 | * `MediaStore`提供者 89 | * 媒体路由 90 | * 支持外部播放 91 | * `Google Cast`和`ChromeCast` 92 | * 10英寸UI 93 | * 把所有电视放在一起:`Decktastic` 94 | * 创建一个媒体路由提供者 95 | * 截屏和屏幕录制 96 | 97 | ####安全 98 | * SSL 99 | * 加密存储 100 | * 高级权限 101 | * `RestrictedProfiles`和`UserManager` 102 | * 触屏劫持 103 | * 多种多样的安全技术 104 | 105 | ####硬件和系统服务 106 | * `AlarmManager`和`Scheduled Service Pattern` 107 | * `PowerManager`和`WakeLocks` 108 | * `JobScheduler` 109 | * 适应基于位置的服务 110 | * 融合位置提供者 111 | * 使用剪切板 112 | * `Telephony` 113 | * 使用`SMS` 114 | * `NFC` 115 | * 设备管理 116 | * 传感器的基本使用 117 | * 打印和文档生成 118 | * 处理不同的硬件 119 | 120 | ####集成和内省 121 | * 编写和使用Parcelables序列化 122 | * 响应`URLs` 123 | * 插件模式 124 | * `PackageManager`诀窍 125 | * 远程服务和绑定模式 126 | * 高级`Manifest`技巧 127 | * 多种多样的集成要诀 128 | * 可复用组件 129 | 130 | ####其它工具 131 | * `Android Studio`对话框和编辑器 132 | * 高级模拟器功能 133 | * `Lint`和`Support Annotations` 134 | * 截屏和屏幕录制 135 | * ADB要诀和技巧 136 | * 发现CPU瓶颈 137 | * 发现内存泄露 138 | 139 | ####Android应用调优 140 | * 速度问题 141 | * 发现CPU瓶颈 142 | * NDK 143 | * 发现和排除`JANK` 144 | * 带宽问题 145 | * 聚焦:`TrafficStatus` 146 | * 测量带宽使用 147 | * 让带宽变得智能 148 | * 应用堆问题 149 | * 发现内存泄露 150 | * 系统内存问题 151 | * 电池生命问题 152 | * 其他电源测量选项 153 | * 电源消耗的来源 154 | * 解决应用大小问题 155 | 156 | ####脚本语言 157 | * 脚本语言的角色 158 | * 用于Android的脚本层 159 | * JVM脚本语言 160 | 161 | ####作为替代的应用开发选项 162 | * 作为替代环境的角色 163 | * HTML5 164 | * 其他作为替代的环境 165 | 166 | ####多种多样的话题 167 | * 使用`ACRA`的闪退报告 168 | * 应用内诊断 169 | * 反对的模式 170 | 171 | ####控件目录 172 | * `AdapterViewFlipper` 173 | * `CalendarView` 174 | * `DatePicker` 175 | * `ExpandableListView` 176 | * `SeekBar` 177 | * `SlidingDrawer` 178 | * `StackView` 179 | * `TabHost` 180 | * `TimePicker` 181 | * `ViewFlipper` 182 | 183 | ####设备目录 184 | * `Chrome`和`Chrome OS` 185 | * `Kindle Fire` 186 | * `BlackBerry` 187 | * 穿戴式设备 188 | * Google 电视 189 | * Amazon Fire 电视 190 | 191 | ####附录 192 | * 附录A:CWAC Libraries 193 | * 附录B:N开发者预览版 194 | * 附录C:社区剧院和基于应用的训练 195 | -------------------------------------------------------------------------------- /Preface/Warescription.md: -------------------------------------------------------------------------------- 1 | ###`Warescription` 2 | 3 | 但愿你是是借助`Warescription`阅读这本电子书的。 4 | 5 | 在你订阅期间,`Waresciption`给与你了这本书的PDF,EPUB以及Kindle(MOBI/kf8)格式的电子版本及其更新。你也能使用这本书的apk文件版,连同快速全文搜索。在订阅期间你也可以获取其他`CommonsWare`可能发布的书。 6 | 7 | 每个订阅者在每个版本上都能有带有姓名的标题。这样的话,你的书籍永远不会过时太久,当有更新内容时候你就能把它们应用上去。例如为了力求准确,当有新的可用`Android SDK`版本时这本书很快就会根据API中的改变进行更新。 8 | 9 | 但是,你只能够在你拥有激活状态的`Waresciption`的时候才能对书籍进行下载。在你的`Waresciption`结束之后,在下个更新出来之前你仍旧可以下载这本书。之后,你就不能再下载这本书了。因此,请在更新一出来就去下载。当这本书的新版本发布的时候,你可以通过以下方式得知: 10 | 11 | 1.CommonWare Twitter简讯 12 | 13 | 2.CommonsBlog 14 | 15 | 3.`Warescription`新闻邮件,你可以在`Warescription`上进行订阅 16 | 17 | 4.每一或两个月核对下`Warescription`网站 18 | 19 | 订阅者也可以得到其它好处,包括: 20 | 21 | * "办公时间"-在线谈话来帮助你解答Android开发中遇到的问题。你会在你的`Warescipiton`上发现关于此项内容的日历。 22 | 23 | * Stack Overflow “bump”服务,让你发布在上面而没有一个满足要求的答案的问题获取额外关注。 24 | -------------------------------------------------------------------------------- /Preface/WelcometotheBook.md: -------------------------------------------------------------------------------- 1 | 2 | ###欢迎来看这本书 3 | 4 | 谢谢! 5 | 6 | 谢谢你对Android开发应用的这份兴趣。短短几年间,Android无疑成长为了世界上最流行的智能手机操作系统。 7 | 不管你是给公众还是你的公司或是组织开发应用程序,又或者是仅仅自己试验下,我相信你会觉得Android是 8 | 一个令人激动而又有挑战的探索领域。 9 | 10 | 并且,最重要的,谢谢你对这本书的兴趣。我衷心希望它对你有帮助,最起码让你感觉偶尔是有趣的。 11 | -------------------------------------------------------------------------------- /Preface/WhatsNewInVersion7.3.md: -------------------------------------------------------------------------------- 1 | ###版本7.3有什么更新 2 | 3 | 针对那些已经读过这本书前一版的人,这里有一些关于7.3版本所新增内容的强调突出: 4 | 5 | * 针对AndroidStudio 2.1对本书进行了跟新,包括一大章使用模拟器的内容,涵盖了许多新模拟器的特性。 6 | 7 | * 扩大了附录中关于N开发者预览版,更新到了N开发者预览版2,并添加了`TileService`和网络安全 8 | 配置的材料。 9 | 10 | * 扩大了通过存储访问框架使用文档的涵盖范围,包扩涵盖了`ACTION_OPEN_DOCUMENT_TREE`和 11 | Android N的`StorageVolume`选项 12 | 13 | * 在Android N附录和存储访问框架中都扩大了Android N多窗口的范围,后一个中添加了 14 | 多页签/多窗口文本编辑的样例 15 | 16 | * 把`JUnit`和`JUnit4`这两章合并成一章,以及关于测试的主要章节的修改中和基于Android 2.1的更新 17 | 18 | * 更新`Notification`的范围来改善关于进度通知和自定义视图的材料,覆盖了Android N的在锁屏上的 19 | 快速回复,为了处理好Android N,使用`FileProvider`对象而不是`File`对象 20 | 21 | * 扩大了`preferences`的覆盖范围来包含`MulitSelectListPreferences`和带有动态内容的ListPreferences。 22 | 23 | * 添加了更多关于`StreamProvider`的内容,作为`FileProvider`的替代方案 24 | 25 | * 移除了触屏劫持的那章,把相关部分的材料已到了各种各样的安全技巧那章。 26 | 27 | * 删除了关于`ActionBarSherlock`和非Android穿戴设备的过时内容 28 | 29 | * 移除了关于`ViewPaggerIndicator`的材料 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #忙碌码农的Andorid开发指南 2 | 3 | 这是一本正在翻译中的书,翻译的是Mark L.Murphy的The Busy Coder's Guide to 4 | Android Development。 5 | -------------------------------------------------------------------------------- /RecyclerView/AdapterViewanditsDiscontents.md: -------------------------------------------------------------------------------- 1 | 2 | ###AdapterView及对它的不满 3 | 4 | AdapterView,特别是它的子类ListView和GridView,在Android应用开发中更是承担了重要的职责。对基本场景来说,它们还是相当令人满意的。 5 | 6 | 但是,存在问题。 7 | 8 | 可能最大的策略性的问题是更新一个AdapterView的时候,往往是要么全部更新要么不更新。如果模型数据改变了——新的行添加了,存在的行移除了或者数据改变了这些可能影响AdapterView的展现的行为-唯一提供很好支持的解决方案是调用notifyDataSetChanged()并让AdapterView重新构建自己。这个过程事缓慢的并且可能对像选择状态这样的事物有影响。如果你真的想要对进行复杂的改变,并且在行添加或移除的时候使用动画效果,这已经没有一半的可能性了。 9 | 10 | 战略上来说,AdapterView,AbsListView(ListView和GridView的直接父类),和ListView对许多门外汉来说就是一团乱麻。这些类中堆砌了太多的职责,以至于对Google来说可维护性是一种挑战,扩展性就更可以说是不切实际了。 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /RecyclerView/EnterRecyclerView.md: -------------------------------------------------------------------------------- 1 | ###进入垃圾回收视图 2 | RecyclerView就是为弥补这些瑕疵而设计的。 3 | 4 | RecyclerView它自己本身除了帮助管理视图回收(例如:竖直列表的行回收)之外做了很少的工作。它几乎所有其它的东西给委托给了其它的类,例如: 5 | 6 | * layout manager,负责把视图组织成多样的结构(竖直列表,网格,交错网格,等等) 7 | * item decorator,负责给视图应用效果和光定位,例如在竖直列表之间加上分隔线 8 | * item animator,负责在模型数据改变的时候的动画效果 9 | 10 | 这是在需要你熟练掌握adapters和view holders(常见AdpterView使用方法的优质标志)的。 11 | 12 | 因为layout manager是通过抽象类和可更换的具体措施来进行处理的,第三方开发者可以选择共享给开发者使用,就像Google做的那样。 13 | [在本章稍后内容中](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/blob/master/RecyclerView/TheMarchoftheLibraries.md),我们会来探索一些这种第三方类库。 14 | 15 | 另一方面,虽然RecyclerView没有像ListView或GridView那么现成可用。在recyclerview-v7库中,并不是所有东西都没了,而是需要你自己动手实现或依赖于第三方类库实现。 16 | 17 | 18 | -------------------------------------------------------------------------------- /RecyclerView/Grids.md: -------------------------------------------------------------------------------- 1 | ###网格 2 | 3 | 到目前为止,我们专注的是把模型数据集合的视觉展现在竖直滚动的列表中。在AdapterView家族中,给定的AdapterView子类有着特定的视觉表现(Listview是竖直滚动的,GridView是二维网格等等)。在使用Recyclerview的时候,布局管理器的选择决定了绝大部份的视觉展现,而且从列表切换到网格简单到只要改变一行代码。 4 | 5 | 尽管如此,关键的是取决于你要的是什么的,网格形势的RecyclerView会更复杂,只不过是因为你现在有了两个维度来进行配置的权利。 6 | 7 | ####样例网格 8 | 9 | 要让RecyclerView使用网格是把LinearLayoutManager换成GridLayoutManager的问题。在RecyclerView/Grid的样例项目中,你会看到CardRippleList3样例应用的一个拷贝,现在在其中的MainActivity的OnCreate()方法中使用的是GridLayoutManager。 10 | 11 | 12 | @Override 13 | public void onCreate(Bundle icicle){ 14 | super.onCreate(icicle); 15 | 16 | setLayoutManager(new GridLayoutManager(this,2)); 17 | setAdapter(new IconicAdapter()); 18 | } 19 | 20 | 21 | GridLayoutManager把跨度和上下问,作为构造器的参数。在样例中,跨度等于列数:每个由RecyclerView.Adapter返回的项会进入一个单行单跨度的单元。 22 | 23 | 在我们的例子中,我们请求了两个跨度,结果就变成了两列。 24 | 25 | 在此例中,有一个真的有行有列的单元格组成的网格。因此,行的高度是有行中最高的单元格决定的。举个例子,“amet单元格”比它所需的高是因为同一行的“consectetuer”单元格。在这章的之后内容中,我们会检视另外一个选项,StaggeredGridLayoutManager,在里面单元格不必要整齐的排列。 26 | 27 | ####选择列的数量 28 | 29 | 如果我们旋转这个样例的屏幕,你会决定看起来好一点,因为它们是改变用途为列表样式行了。 30 | 31 | 32 | 但是,一些应用可能有很小的单元。此外,我们还要考虑平板,甚至可能电视。你可能需要给予屏幕尺寸和方向来决定垮度。 33 | 34 | 一种尝试是使用整型资源。你可以有一个有元素的res/values/ints.xml文件,给出整型的名称和值。你也可以有res/values-w600dp或其它资源变化,这样你就能给不同的屏幕尺寸提供不同的值。然后,在运行时,调用getResources().getInteger()来获取给当前设置使用的资源的正确值,并在你的GridLayoutManager构造器中使用。现在你能通过提供给构造函数的跨度来控制存在多少列了。 35 | 36 | 另一种尝试是,Chiu-ki Chan提议的,创建一个RecyclerView的一个子类,在其中你提供了一个自定义属性给大致的列宽度。然后在你的子类的onMeasure()方法中,你可以计算出跨度的数量从而得出你想要的列宽度。 37 | 38 | 当然,另一种利用屏幕控件的方式是增大单元格。默认情况下,它们会均匀增大,因为每个单元格占据一个跨度,并且跨度是均匀大小的。但是,你可以通过附加一个GridLayoutManager.SpanSizeLookup到GridLayoutManager改变这个行为.GridLayoutManager是用于负责指示给位置的项应该占据网格的多少跨度的。我们会在这章之后内容进行调查它是怎么工作的。 39 | -------------------------------------------------------------------------------- /RecyclerView/OtherBitsofGoodness.md: -------------------------------------------------------------------------------- 1 | ###其他的好东西 2 | 引用著名美国专题广告牌的话:”等一下,还有呢!" 3 | 4 | 除了LinearLayoutManager和GridLayoutManager之外,还有StaggeredGridLayoutManager.使用竖直滚动的GridLayoutManager的话, 5 | 行都是一样高的,但是宽度是多变的。使用竖直滚动的StaggeredGridLayoutManager,列都是一样高的,但是高度可能不一样。 6 | 7 | 三个标准的layout manager同样也支持横向操作,只要改下构造器的一个布尔值就可以。在这些情形中,内容是横向滚动的而不是竖直的。这就不需要第三方 8 | 类库像ListView那样的实现了。 9 | 10 | 并且,当然,你可以实现你自己的Recycler.LayoutManager,而不使用任何内置的。 11 | -------------------------------------------------------------------------------- /RecyclerView/Prerequisites.md: -------------------------------------------------------------------------------- 1 | ###准备工作 2 | 3 | 为了理解这章需要你已经读了核心章节,特别是[AdapterViews和adapters](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/AdapterViewsAndAdapters)那章。 4 | 5 | 一节包含了[自定义XMLdrawables](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/CustomDrawables).另一节展示使用的内容是从[MediaStoreProvider](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/TheMediaStoreProvider)拉取的。 6 | 7 | 这章也包含了像[action modes](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/ActionModes)和其它的[高级ListView技巧](https://github.com/jinyulei0710/The-Busy-Coder-s-Guide-to-Android-Development/tree/master/AdvancedListViews)。 8 | -------------------------------------------------------------------------------- /RecyclerView/README.md: -------------------------------------------------------------------------------- 1 | ##RecyclerView(垃圾回收视图) 2 | 直观表示多个条目的集合是许多移动应用的一个很重要的方面。这项功能的经典Android实现,是由AdapterView控件家族: 3 | ListView,GridView,Spinner等完成的。但是,它们存在一定局限性,特别是涉及到列表内容动画变化的高级功能的时候。 4 | 5 | 在2014年,Google通过Android支持包发布了RecyclerView。开发者可以添加recyclerview-v7到它们的项目中 6 | 并使用RecyclerView作为大部分AdapterView家族的一个替代方案。RecyclerView是一个全新的更为灵活的容器, 7 | 有着很多的钩子和代理从而允许行为的插入。 8 | 9 | 这主要有两个影响: 10 | 11 | 1.Recyclerview确实比起对应的Adapterview要强大的多. 12 | 13 | 2.RecyclerView不能拿来就用,甚至于复现基础的ListView/GridView功能也要写相当多的代码。 14 | 15 | 在这章中,我们会从零开始学习RecyclerView,从基本操作开始。其它地方的许多ListView的例子会在这复现, 16 | 来看如何使用RecyclerView完成相同的事情。并且我们会探究一些增加的功能,这些功能或许能让RecyclerView在高 17 | 端Android应用上值得为之付出努力。 18 | -------------------------------------------------------------------------------- /RecyclerView/TheMarchoftheLibraries.md: -------------------------------------------------------------------------------- 1 | ###进击的类库 2 | 3 | 在这个时候,你可能为了让RecyclerView能使用所做的大量工作,无法抑制你的愤怒并扯掉你的衣服。 4 | 5 | (专业建议:不要在公共场合脱衣服,避免触犯法律) 6 | 7 | 毫无疑问RecyclerView是需要自己装配的典型代表。但是,其他开发者带着能弥补这些缺口的类库走到台前,让你不用全部自己去做。 8 | 9 | 注意作者没有尝试很多这些类库,并且列在这里的并不代表认可,也不是对没有列在这里的类库的打击。 10 | 11 | ####DynacmicRecyclerView 12 | 13 | DynamicRecyclerView 类库提供了: 14 | 15 | * 通过自定义的onItemTouchListener实现对项的拖放 16 | * 通过自定义的onItemTouchListener实现水平滑动移除 17 | * 类似这章展示的选择模式 18 | * 使用另一个自定义的onItemTouchListener实现点击样式事件。 19 | 20 | ####Advanced RecyclerView 21 | 22 | Advanced RecyclerView 类库提供了它自己的拖放以及滑动移除实现。 23 | 你在你的RecyclerView.Adapter和RecyclerView.ViewHolder类上实现了支持拖放或滑动移除的接口,外加使用管理类 24 | 进行支持绑定,而不是使用OnItemTouchListener实现。 25 | 26 | 它也支持展开项,点击项时展开或收拢位于下方的视图,提供作为ExpanableListView的替代尝试。并且,它有着一些item装饰, 27 | 包括基本的分隔线实现。 28 | 29 | ####SuperRecyclerView 30 | 31 | SuperRecyclerView类库有着它自己的滑动移除实现。它也支持“swipe layout”模式,当水平滑动出现的时候,去除项上的一系列上下文操作。 32 | 33 | 它也提供了: 34 | 35 | * scrollbars(RecyclerView没有的) 36 | * 处理数据异步加载的进度条和空视图 37 | * 一个无休止的或无限滚动的实现,当用户滚动到数据底部的时候,你有着获取更多数据的机会 38 | * sticky headers,当用户滚动的时候,最顶部的头牵制在RecyclerView的顶部,直到新的头划到顶部。 39 | 40 | 但是,这个类库需要你继承一个自定义的RecyclerView子类。 41 | 42 | ####FlexibleDivider 43 | 44 | FlexibleDivider类库做的只有一件事,提供分隔线。但是,它提供了对分隔线的深度支持,使用它你可以很简单地控制 45 | 所有类型的样子,从颜色宽度到边距以及path效果(例如:虚线对比实线)。 46 | 47 | RecyclerView/FlexDividerList样例项目是之前ManualDividerList样例的一个复制,只是现在的分隔线是由FlexibleDivider类库提供了, 48 | 这个类库是通过build.gardle文件加载的: 49 | 50 | dependencies{ 51 | compile 'com.android.support:recyclerview-v7:22.2.0' 52 | compile 'com.yqritc:recyclerview-flexibledivider:1.0.1' 53 | } 54 | 55 | 然后我们使用类库的HorizontalDividerItemDecotation来设置我们的分割线: 56 | 57 | @Override 58 | public void OnCreate(Bundle icicle){ 59 | super.onCreate(icicle); 60 | setLayoutManager(new LinearLayoutManager(this)); 61 | 62 | RecyclerView.ItemDecoration decpr=new HorizontalDiverItemDecoration.Builder(this) 63 | .color(getResouces().getColor(R.color.primary)).build(); 64 | getRecyclerView().addItemDecoration(decor); 65 | setAdapter(new IconicAdapter()); 66 | } 67 | 68 | 结果是实心蓝色分隔线: 69 | 70 |  71 | 72 | 当然,通过这个类库,你可以通过他的建造者样式的API改变更多而不只是它的颜色。 73 | -------------------------------------------------------------------------------- /RequestingPermissions/README.md: -------------------------------------------------------------------------------- 1 | ##请求权限 2 | 3 | 在上世界90年代后期,蜂拥而至的病毒使用从`Microsoft Outlook`收集而来的联系人信息通过投递邮件的方式在互联网上传播开来。病毒只不过是进行了将邮件自我复制,然后发送给Outlook中有有着电子邮件地址联系人。这在当时是可能的,Outlook没有采取任何步骤去阻止应用程序使用Outlook的API,因为API是为普通的开发者而设计的,而不是病毒制造者。 4 | 5 | 现如今,许多应用需要用户明确授权其它应用程序能访问联系人信息的方式来保证数据安全。这些权限可以逐项给予也可以在安装的时候一次性给予。 6 | 7 | 当它需要应用的读或写联系人数据权限的时候,Android别无二致。Android的权限系统不至用于联系人数据,也用于由Andorid框架所提供的内容提供者和服务。 8 | 9 | 你作为一个Andorid开发者,经常需要确保你的应用有着合适的权限去做那些你想对其他应用数据的事情。这章就涵盖了这个话题,包括用于`Android6.0`之前的针对所有权限的经典方式和`Andorid 6.0`以上用于某些权限的新的运行时权限系统。 10 | 11 | 当你开放你的数据或服务给其它Andorid组件的时候,你可能也需要为其它应用使用你的数据或服务去选择请求权限。这会在本书稍后一章中进行讨论。 12 | 13 | 14 | 目录: 15 | 16 | * 经常被问及的关于权限请求的问题 17 | * 权限的特征 18 | * 旧应用中的新权限 19 | * `Android 6.0`以上的运行时系统 20 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/API-VersionedResources.md: -------------------------------------------------------------------------------- 1 | ###API版本控制的资源 2 | 3 | 就像之前在这章中指出的,-vNNN系列后缀指示了这个目录中的资源是针对规定的API等级或者更高的等级的。 4 | 所以,例如,res/values-v21/指示的是这个目录中的资源应该只能在API等级21(Android 5.0)和更高的上使用。 5 | 运行较老Android版本的设备会忽略这些资源。 6 | 7 | 这对于处理主要的Android版本变更是一个重要的系列后缀。固有的Android应用在API等级11(Android 3.0) 8 | 和API等级21(Android 5.0)的时候,观感上发生了巨大的变化。你可能发现在这些API等级分界点你开始有了 9 | 不同的资源,所以你的UI在所支持的所有的Android版本上看起来都是恰如其分的。 10 | 11 | ####用例:API等级的主题 12 | 这个特性的一个重大的用例是以API等级区分不同主题。 13 | 14 | 即使你的`minSdkVersion`是11或者更高的版本,你的应用中可能存在两个不同的主题: 15 | 16 | * 一个是基于`Theme.Holo`的,被使用在API等级11-20 17 | * 另一个是基于`Theme.Material`的,从API等级21起开始使用 18 | 19 | 你粗暴的替代方案是使用`action bar`的`appcompat-v7`向后兼容方案和一些`Material Design`审美。 20 | 对于高度程式化的应用来说,或者你确定要在Android 5.0之前的设备上使用`Material Design`,`appcompat-v7` 21 | 是值得考虑的。但是如果你想要更好地在每个主要的UI变种上进行混合,你会想要在Android 3.x和4.x上支持 22 | Theme.Holo,并且在之后的版本上使用Theme.Material。 23 | 24 | 这里的繁重工作是设置你的主题,就像`action bar`那章概述的那样。让它们同时可用,基于 25 | 于设备版本来说,仅仅是一个把资源放进合适的目录中的问题。 26 | 27 | 例如,看下ActionBar/VersionedColor这个样例项目。这是HoColor和MaterialColor样例项目 28 | 的混合,基于API等级决定使用哪个主题。 29 | 30 | 在res/values/目录中,我们有一个和在HoloColor样例中一样的styles.xml文件,指示 31 | 名字标准化成了styles.xml。它使用了一个由Action Bar样式生成器生成的自定义主题 32 | (Theme.Apptheme)。 33 | 34 | 也存在一个指示values资源在API等级和更高版本上使用的res/values-v21/目录。 35 | 它有着最初在MaterialColor样例中看到的主题,其中主题资源被重命名成了Theme.Apptheme, 36 | 来对应定义在res/values/的那个。 37 | 38 | 然后,引用Theme.Apptheme,我们就在正确的设备上得到了正确的 39 | `action bar`。 40 | 41 | 这里,让主题资源名称保持一致是很重要的,因为我们在元素中引用了这个名称。 42 | 为了能拉取正确的那个,我们需要它们都是同样的名称。但是,至于这些主题所引用的资源,例如颜色 43 | 或者drawable资源,进不进版本控制的目录,就随你瞧着办了。如果你想要多个版本,其中API等级 44 | 选择使用哪个版本的话,它们必须到版本控制的目录中并且要有相同的名称。 45 | 46 | 例如,定义在res/values-v21/styles.xml的基于Theme.Material的主题引用了三个颜色资源。 47 | 这些资源的文件(colors.xml)恰好也在res/values-v21/中。但是,因为我们没有基于API等级 48 | 去放置这些颜色,放置在res/values/的colors.xml也能很好的工作。并且,如果我们不想要 49 | 因API等级的不同而有不同的颜色,我们需要这些颜色都定义在相关的资源集中,例如在res/values和 50 | res/values-v21/。 51 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/AndNow,aWordFromtheAndroidProjectView.md: -------------------------------------------------------------------------------- 1 | ###来自Android项目视图的一句话 2 | 3 | 在这本书的早先内容中,当介绍AndroidStudio的时候,我们看到了Android项目视图。 4 | 5 | Android被这么创建的众多原因之一是为了帮助你的管理资源,特别是跨越多个资源的时候。 6 | 7 | 例如,这里是一张相同Android项目的截屏,但是这次values资源是在树中展现的: 8 | 9 | 这个树使它看起来仅仅有一个res/values/dimens.xml...但是这个文件不知怎么的有孩子。 10 | 其中一个孩子仅仅是光秃秃的一个dimen.xml文件名,而另一个有附加的“w820dp”。 11 | 12 | 这反映了存在两个版本的dimens.xml的事实:一个在res/values/,一个在res/values-w820dp/: 13 | 14 | 在Android项目视图中,资源是资源进行组织的,而不是以资源集。例如, 15 | 这对于发现所有你要调整资源的一个版本是很有用的。 16 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/BlockingRotations.md: -------------------------------------------------------------------------------- 1 | ###阻碍旋转 2 | 3 | 无疑你已经看过一些Android应用只不过会忽略所有旋转屏幕的尝试。许多游戏就是这么做的,完全在横屏 4 | 模式下操作,不管设备是如何朝向的。 5 | 6 | 为了这么做,添加android:screenOrientation="sensorLandscape",或者也许可能是android: 7 | screenOrientation="sensorPortrait"到你的manifest中去。这些名字的“sensor”部分,指示你的 8 | 应用能够在常规或者这个方向的旋转版(例如,“常规”横屏是设备从竖直状态逆时针旋转90度,同时翻转版横屏是 9 | 从竖屏顺时针旋转90度)。在API等级18以上,你可以换而使用userLandscape或者userPortrait,因为 10 | 这些会尊敬用户的系统级别的选择是否要锁定屏幕,如果没有锁定屏幕默认为sensorPortrait或sensorLandscape的 11 | 行为。 12 | 13 | 理想情况下,你选择landscape,因为一些设备(例如Android电视),只能是水平的。 14 | 15 | 也要注意到Android仍旧把它当成一个配置改变,不管对用户可不可见。因此,你仍旧需要使用之前所提及到的技术 16 | 中的一种去处理这个配置改变和其它改变(例如,底座事件和,区域改变)。 17 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/ChoosingTheRightResource.md: -------------------------------------------------------------------------------- 1 | ###选择正确的资源 2 | 3 | 假定你有一个有着N个不同定义的资源,Android是如何选择一个来使用的呢? 4 | 5 | 首先,Android弃用掉那些明确非法的。所以,例如,如果设备的语言是-ru,Android会忽略 6 | 指定为其它语言(例如,-zh)的资源集。这个弃用有个例外-密度限定和屏幕尺寸限定——我们稍后 7 | 会了解这些例外。 8 | 9 | 然后,Android选择那个有着要求的资源和最重要唯一限定符的资源集。这里,通过”最重要“ 10 | 我们意味着基于以上所讨论的目录命名规则,出现在目录名最左侧的那个。并且,通过“唯一”, 11 | 我们意味着没有其它资源有这个限定符。 12 | 13 | 如果没有对应的特定资源集,Android会选择默认那套——那套资源的目录名上没有后缀(例如,res/layout/)。 14 | 15 | 记住了这些规则,让我们看看一些场景,除了基本情况之外还涵盖上述的例外。 16 | 17 | ####场景#1:一些简单的 18 | 让我们假定我们有一个main.xml文件存在于: 19 | * res/layout-land/ 20 | * res/layout/ 21 | 22 | 当我们调用setContentView(R.layout.main),如果设备是处于横向模式的话,Android会选择 23 | 位于res/layout-land/的main.xml。在此例中这个特定的资源集是合法的,并且它有着最重要的 24 | 唯一限定符(-land)。如果设备是处于纵向模式,res/layout-land/资源集就不能胜任了,并且所以 25 | 它就被丢弃了。这就给我们剩下了res/layout/,所以Android使用了这个版本的main.xml。 26 | 27 | ####场景#2:毫不相干的资源集种类 28 | 尽管很奇怪,有可能main.xml位于: 29 | 30 | * res/layout-en/ 31 | * res/layout-land/ 32 | * res/layout/ 33 | 34 | 在此例中,如果设备的地域被设置成了英语,不管设备的方向是什么Android会选择 35 | res/layout-en/。这是因为-en是一个更为重要的资源集限定符——在来自Android文档的“表2.配置限定符名称”中 36 | ”语言和地域“比"屏幕方向"的优先级要来的高。不过如果设备没有设置成英语,Android会丢弃掉这个 37 | 资源集,就这一点来说决策过程是和以上的场景#1一样的。 38 | 39 | ####场景#3:多样的限定符 40 | 41 | 让我们设想有一个项目,其中main.xml存在于: 42 | 43 | * res/layout-en/ 44 | * res/layout-land-v11/ 45 | * res/layout/ 46 | 47 | 你可能认为res/layout-land-v11/是所选择的,因为它更加明确,对比其他资源集 48 | 的一个或没有来说,它对应两个资源限定符。 49 | 50 | 尽管如此,在此例中,语言是比屏幕方向或者Android API 等级更为重要的,所以 51 | 决策过程是和以上的场景#2类似的:Android对于英语会选择res/layout-en/, 52 | 对于水平的API等级11以上的设备会选择res/layout-land-v11,又或者 53 | 对于所有其它的会选择res/layout/。 54 | 55 | ####场景#4:再访多样的限定符 56 | 让我们改变资源的混搭,现在我们有一个项目,其中带有main.xml存在于: 57 | 58 | * res/layout-land-night/ 59 | * res/layout-land-v11/ 60 | * res/layout/ 61 | 62 | 这里,虽然-land是最重要的资源限定符,但不是唯一的——我们有着 63 | 不止一个带有-land的资源集。因此,我们需要去核对次重要的资源集限定符。 64 | 在此例中,次重要的就是-night,因为夜间模式是比AndroidAPI等级更为重要的类别, 65 | 所以如果设备是处于夜间模式的时候,Android会选择res/layout-land-night。 66 | 否则的话,如果设备运行在API等级11或更高之上它会选择res/layout-land-v11/。 67 | 如果设备不是处于夜间模式并且也没有运行在API等级11或者更高的版本之上, 68 | Android会选择res/layout/。 69 | 70 | ####场景#5:屏幕密度 71 | 现在,让我们看下规则的首个例外:屏幕密度。 72 | 73 | Android总是会接收包含屏幕密度的资源集,即使它与设备的密度不相配。当然, 74 | 如果有一个精确的密度匹配,Android会使用它。否则的话,它会基于它与设备的实际密度以及 75 | 是否有其它比设备的实际密度高或低的设备来使用它觉得次好的匹配。 76 | 77 | 原因是对于drawable资源来说,Android会向下或者向上自动采样图片, 78 | 所以drawable会是正确的大小,即使你没有在某一密度中提供图片。 79 | 80 | 隐情是双方面的: 81 | 82 | 1.Android应用这个逻辑到了所有的资源,而不仅仅是drawable,所以 83 | 即使没有精确匹配的密度,比如说,一个layout,Android仍旧会从另一个密度的 84 | 存储桶中来为layout进行选择 85 | 86 | 2.作为上一步的副作用,如果你包含了一个密度资源集限定符,Android会忽略 87 | 所有低优先级的资源集限定符 88 | 89 | 所以,现在让我们假装我们的项目的main.xml位于: 90 | 91 | * res/layout-mdpi/ 92 | * res/layout-nonav/ 93 | * res/layout/ 94 | 95 | Android会选择res/layout-mdpi/,即使对于没有“非接触式导航方法”的-hdpi设备。 96 | 虽然-mdpi并不和-hdpi匹配,Android仍旧会选择-mdpi。如果我们要对 97 | drawable资源进行处理,Android会向上采样-mdpi图片。 98 | 99 | ####场景#6:屏幕尺寸 100 | 101 | 如果你有着和屏幕尺寸绑定的资源集,Android会选择最接近实际屏幕尺寸而依然比 102 | 实际尺寸小的。比实际尺寸大的屏幕尺寸的资源集是被忽略的。 103 | 104 | 对于所有设备来说,这适用于-swNNNdp,-wNNNdp,以及-hNNNdp。在-large或者 105 | -xlarge的设备上,Android对传统的屏幕尺寸限定符(-small,-normal,-large, 106 | -xlarge)应用了相同的逻辑。但是对于-small或-normal设备Android没有应用相同 107 | 的逻辑——一个-normal设备不会加载一个-small资源。 108 | 109 | 现在让我们假装我们的项目有main.xml位于: 110 | 111 | * res/layout-normal/ 112 | * res/layout-land/ 113 | * res/layout/ 114 | 115 | 如果设备不是-small的,Android会选择res/layout-normal/。否则的话, 116 | 如果设备是横向的,Android会选择res/layout-land。如果所有其它的都失败了, 117 | Android会选择res/layout/。 118 | 119 | 相似的,如果我们有: 120 | 121 | * res/layout-w320dp/ 122 | * res/layout-land/ 123 | * res/layout/ 124 | 125 | 对于当前屏幕宽度是320dp或者更高的设备,Android会选择res/layout-w320dp/。 126 | 否则的话,如果设备是横向的,Android会选择res/layout-land。如果所有其它的都失败了, 127 | Android会选择res/layout/。 128 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/ConfigurationsandResourceSets.md: -------------------------------------------------------------------------------- 1 | ###配置和资源集 2 | 3 | 一套资源不可能合适你应用的所有被使用的情形。一个显而易见的地方就是字符串资源和处理国际化和本地化。 4 | 把所有字符串放进一种语言的时候运作良好——至少对于开发者来说可能是的——但是只涵盖了一种语言。 5 | 6 | 话虽这样说,这不是唯一一个资源可能需要有差别的情形。这里还有其它的: 7 | 8 | 1.屏幕方向:屏幕是纵向的还是横向的? 9 | 10 | 2.屏幕尺寸:手机尺寸大小的?平板尺寸大小的?电视尺寸大小的? 11 | 12 | 3.屏幕密度:屏幕上每英寸有多少个像素点?我们需要一个较高分辨率版本的图标,那么它就不会 13 | 看起来太小? 14 | 15 | 4.键盘:用户有什么键盘(全键盘,数字键盘,都不是),或者现在是作为一个选项 16 | 17 | 5.其它输入方式:设备有像手写板或鼠标这样其他形式的输入方式吗? 18 | 19 | 当前Android处理这个的方式是持有多个资源目录,它们的每个名字中都嵌入了条件。 20 | 21 | 例如,假如你想要同时支持英语和西班牙语字符串。通常,对于单语言的设置,你会把你的字符串 22 | 放进一个被命名为res/values/strings.xml的文件中。为了同时支持英语和西班牙语,你可以创建 23 | 两个文件夹,res/values-en/和res/values-es/,其中连字符后面的值是用于表示你想要语言的 24 | [ISO639-1]的两个字符。你的英语字符串会到res/values-en/strings.xml中去,西班牙语的 25 | 会到res/values-es/strings.xml中去。Android会基于用户的设备设置选择适合的文件。注意Android 26 | 5.0中添加了BCP 47 三个字符的语言和本地化值,虽然这些也需要Android 1.1.0(或更高)的Gradle和 27 | Android Studio 1.1.0(或更高)版本。 28 | 29 | 但是,对于你来说更好的方式是考虑某种语言作为你的默认语言,并把那些字符串放进res/values/strings.xml。 30 | 然后,为你所翻译的创建另一个资源目录(例如,为西班牙语创建res/values-es/strings.xml)。 31 | Android会尝试匹配一个特定语言的资源集合,如果失败的话,它会回退到默认的res/values/strings.xml。 32 | 这样的话,如果你的应用存在于不是你所预料的语言设备的话,你至少可以提供你选择的默认语言。否则的话, 33 | 你会以一个`ResourceNotFoundException`异常而告终,并且你的应用会崩溃。 34 | 35 | 因此资源集合战略的基本原则是:在默认的目录(例如,res/layout/)中有完整的一套资源, 36 | 并且与某些所需的特定配置绑定的资源集中(例如,res/layout-land/)覆盖这些资源。 37 | 38 | 注意,Android有一个为了帮助你管理默认语言和你所要包含进你应用的任意翻译的字符串资源的 39 | 翻译编辑器。 40 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/CopingwithComplexity.md: -------------------------------------------------------------------------------- 1 | ####应对各种错综复杂的状况 2 | 3 | 当你需要使用多个用于你的资源的毫不相干的条件的时候,事情就开始变得复杂了。 4 | 5 | 例如,假定你有着依赖于地域的drawable资源,例如一个停止标志。你可能想要让drawable资源集与语言 6 | 进行绑定,所以在不同的地域中使用不同的图片。但是,你可能也希望这些图片会因密度的不同而不同, 7 | 较高密度的设备上使用较高分辨率的图片,所以图片出来的话大致会是相同实际大小。 8 | 9 | 为了这么做,你要产生带有多个资源集限定符的多个目录,例如: 10 | 11 | * res/drawable-ldpi/ 12 | * res/drawable-mdpi/ 13 | * res/drawable-hdpi/ 14 | * res/drawable-xhdpi/ 15 | * res/drawable-en-rUK-ldpi/ 16 | * res/drawable-en-rUK-mdpi/ 17 | * res/drawable-en-rUK-hdpi/ 18 | * res/drawable-en-rUK-xhdpi/ 19 | * 等 20 | 21 | 一旦你进入这些类型的情形中,一些规则就开始生效了,例如: 22 | 23 | 1.配置选项有着特定的优先顺序,并且在目录中它们必须以那个顺序出现。Android文档 24 | 中概述了这些操作能够出现的特定顺序。就这个样例的目的来说,屏幕尺寸会比 25 | 屏幕方向重要些,比屏幕密度重要些,比是否有键盘重要些。 26 | 27 | 2.每个目录上每个配置选项种类的值只能有一个 28 | 29 | 3.选项是大小写敏感的 30 | 31 | 例如,基于屏幕尺寸和方向你可能想要有不同的布局。因为在资源系统中屏幕 32 | 尺寸是比方向重要的,屏幕尺寸在目录名中会出现在方向之前,例如: 33 | 34 | * res/layout-sw600dp-land/ 35 | * res/layout-sw600dp/ 36 | * res/layout-land/ 37 | * res/layout/ 38 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/DefaultChangeBehavior.md: -------------------------------------------------------------------------------- 1 | ###默认的变化行为 2 | 3 | 当你在Android SDK调用加载资源的方法(例如,前面提到的setContentView(R.layout.main)), 4 | Android会走查这些资源集,找到对于要求的来说正确的资源,并使用它。 5 | 6 | 但是如果配置改变发生在我们请求资源之后呢?例如,如果之前用户是竖着握着他们的设备的,然后旋转 7 | 到横屏?如果-land版本存在的话,我们会要一个布局的-land版本。并且,因为我们已经请求过资源了, 8 | 除了强迫我们再次请求这些资源之外,Android没有在运行中修改资源的方法。 9 | 10 | 所以,当运行中配置改变了,这就是默认情况下Android对我们的前台activity所做的事情。 11 | 12 | ####销毁并重建Activity 13 | Android所做的最重大的事情是销毁并重建我们的activity。换句话说: 14 | 15 | * Android在我们最初的activity实例上调用了onPause(),onStop()以及onDestroy() 16 | * Android使用相同的用来创建最初实例的Intent来创建一个崭新的相同的activity类实例 17 | * Android在新的activity实例上调用onCreate(),onStart()以及onResume() 18 | * 新的activity出现在屏幕上 19 | 20 | 这可能看起来是侵入性的。你可能不希望Android仅仅因为用户抖了抖手腕并旋转了手机的屏幕, 21 | 就擦除一个非常好的activity。但是这是Android能保证重新请求所有我们资源的唯一方式。 22 | 23 | ####重建Fragment 24 | 25 | 如果你的activity使用的是fragment,新的activity实例会包含旧的activity实例 26 | 相同的fragment。其中包含静态的和动态的fragment。 27 | 28 | 默认情况下,Android会销毁并重建fragment,就像他销毁和重建activity一样。 29 | 但是,正如我们看到的,我们有一个告诉Android为它们保留某个动态实例的选项, 30 | 它会使用被旧的activity所使用的相同的activity,而不是重新创建一个新的 31 | 实例。 32 | 33 | ####重建视图 34 | 35 | 不管Android有没有重新创建所有的fragment,它会调用所有fragment的onCreateView()(外加 36 | 在最初的一套fragment上调用onDestroy())。换句话说,为了把它们注入新的activity实例中, 37 | Android重建了所有的控件和容器。 38 | 39 | ####保留一些控件状态 40 | 41 | Android会持有我们activity和fragment中的一些控件的实例状态。大部分时候,它 42 | 所持有的是明显的用户可改变的状态,例如: 43 | 44 | * 已经输入到Edittext的东西 45 | * 像CheckBox或RadioButton这样的CompoundButton有没有被选中 46 | * 等等 47 | 48 | Android会从旧的activity实例中的控件收集这个信息,把数据搬运到新的activity实例, 49 | 然后更新新的一套控件使其有相同的状态。 50 | 51 | 但是: 52 | 53 | * 控件需要有一个ID来保存它们的状态。如果你是从一个布局资源中inflate出这个控件, 54 | 并且这个控件有android:id值,你就满足要求了。但是,如果你直接在Java代码中创建控件, 55 | 这些控件是没有ID的。你会需要通过调用setId()来给予它们一个ID或自己管理状态(使用之后 56 | 会在这章描述到的onSaveInstanceState()技术)。 57 | 58 | * ID值需要是唯一的。如果有很多控件有着相同的ID,你就会遇到问题。通常,我们出现有多个 59 | 相同ID的控件的情形是这些控件是来自一个适配器的时候,例如一个ArrayAdapter。 60 | 并且,通常来说这些控件是只读的并且没有任何要保存的值。但是,如果你尝试 61 | 通过适配器把用户可修改的控件放入到布局中,否则你会有着有个有着相同ID的可修改控件, 62 | 你会需要自己进行管理(再一次的,使用之后会在这章描述到的onSaveInstanceState()技术) 63 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/README.md: -------------------------------------------------------------------------------- 1 | 资源集和配置 2 | 3 | 当用户以应用在乎的方式使用设备的时候,它们有时候会变化: 4 | 5 | * 用户可能把屏幕从纵向旋转到横向,反之亦然 6 | * 用户可能把设备放到汽车或者书桌底座上,或者把它从底座上移开 7 | * 用户可能把设备放到一个有全键盘的“笔记本底座”上,或者把它从底座上移开 8 | * 用户可能通过应用设置切换到不同的语言,随后回到运行中的应用 9 | * 等等 10 | 11 | 在所有这些例子中,我们可能会要更改我们所使用的资源。例如,我们用于纵向屏幕的布局在横向模式中使用 12 | 的时候可能会太高,所以我们要用一些其它的布局替代。 13 | 14 | 这章会探索如何为这些不同的情形提供可替换的资源——被称为“配置修改”——并且会解释当我们位于前台, 15 | 用户修改配置时我们的activity发生了什么。 16 | 17 | 目录: 18 | 19 | * [配置是什么?以及它们是如何改变的?](/ResourceSetsandConfigurations/What'saConfigurationAndHowDoTheyChange.md) 20 | * [配置和资源集](/ResourceSetsandConfigurations/ConfigurationsandResourceSets.md) 21 | * [屏幕大小和方向](/ResourceSetsandConfigurations/ScreenSizeandOrientation.md) 22 | * [应对错综复杂的状况](/ResourceSetsandConfigurations/CopingwithComplexity.md) 23 | * [选择正确的资源](/ResourceSetsandConfigurations/ChoosingTheRightResource.md) 24 | * [API版本控制的资源](/ResourceSetsandConfigurations/API-VersionedResources.md) 25 | * [默认的变化行为](/ResourceSetsandConfigurations/DefaultChangeBehavior.md) 26 | * [状态保存的多个场景](/ResourceSetsandConfigurations/StateSavingScenarios.md) 27 | * [你的配置改变选项](/ResourceSetsandConfigurations/YourOptionsforConfigurationChanges.md) 28 | * [阻碍旋转](/ResourceSetsandConfigurations/BlockingRotations.md) 29 | * [来自Android项目视图的一句话](/ResourceSetsandConfigurations/AndNow,aWordFromtheAndroidProjectView.md) 30 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/ScreenSizeandOrientation.md: -------------------------------------------------------------------------------- 1 | ###屏幕尺寸和方向 2 | 3 | 我们还没有看到的资源限定符中,最重要的可能是那些与屏幕尺寸和方向有关的。这里,"方向"指的是 4 | 设备是如何被拿着的,纵向或者横向? 5 | 6 | 方向相对简单的,因为你可以使用-port或者-land作为资源限定符限定目录中的资源到一个特定的 7 | 方向。惯例是把横向的资源放进一个-land目录(例如res/layout-land/)中和并纵向的资源放到一个默认 8 | 目录(例如,res/layout/)中。但是,这仅仅是一个惯例,你要的话也是可以使用-port的。 9 | 10 | 屏幕尺寸就稍微有点复杂了,仅仅是因为这些年来可用的方法已经变了。 11 | 12 | ####最初:Android所定义的存储桶 13 | 14 | 回到一开始`Android1.0`的时候,所有的屏幕大小都是一样的——主要是因为只有一个屏幕尺寸, 15 | 并且主要是因为只有一个设备。 16 | 17 | 但是,`Android 1.5`引入了三个屏幕尺寸以及相关的资源限定符,之后又添加了第四个(-xlarge): 18 | 19 | * -small用于屏幕对角线尺寸3“以下的 20 | * -normal用于屏幕对角线尺寸位于3"和5"之间的 21 | * -large用于屏幕对角线尺寸位于5”和10"之间的 22 | * -xlarge用于屏幕对角线尺寸10"以上的 23 | 24 | 正如我们所看到的,这些资源限定符建立了目录的资源值得被使用的下界。所以一个res/layout-normal/ 25 | 不会被-small屏幕使用但是会被-normal,xlarge,和-xlarge屏幕使用。 26 | 27 | ####现代:开发者所定义的存储桶 28 | 29 | 传统的尺寸存储桶有个问题,那就是是相当不灵活。如果你所要考虑的是所谓的“平板手机”,像三星的`Galaxy Note` 30 | 系列,布局是应该更像手机呢,还是应该更像是平板呢,例如8.9"的`kindle Fire HD`,应该有着 31 | 更像是10"平板的布局?这在固定存储桶中是不可能给予的。 32 | 33 | `Android 3.2`给予了我们更多的控制力。使用有点让人困惑的-swNNNdp资源限定符,我们就能 34 | 拥有用于屏幕尺寸的我们自己的存储桶。这里NNN是被你以一个dp为单位值所取代的,代表的是屏幕的 35 | 最小宽度。“最小宽度”大致上意味着当设备以纵向模式握着的时候屏幕的宽度。因此你的自定义存储桶是 36 | 基于最短屏幕那侧的直线距离的,而不是像传统的存储桶那样基于屏幕对角线进行衡量的。 37 | 38 | 例如,假定你想要考虑7"那个点的分隔线——7"和更小的设备会得到一个布局资源集,同时较大的设备会得到 39 | 一个不同的布局集合。在常见长宽比下,7"平板的最短宽度大约是3.5"到3.75"。因为1dp是一英寸的1/160。 40 | 这些最短距离相当于560-600dp。因此,你可能会为你的较大布局设置一个-sw600dp的资源集,并且 41 | 把较小的布局放入默认的资源集中。 42 | 43 | ####混搭:宽度和高度存储桶 44 | 45 | 使用-swNNNdp的时候并没有说明方向,因为最短宽度是和设备是纵向握着还是横向握着是无关的。 46 | 因此,你会需为你所选择的分隔线添加一个`-swNNNdp-land`作为横向资源的资源集。 47 | 48 | 供替换使用的有`-wNNNdp`和`-hNNNdp`.这些资源集限定符是的工作方式和`-swNNNdp`的差不多的,特别是 49 | 就NNN的含义而言。但是,然而`-swNNNdp`指的是最短宽度,`-wNNNdp`指的是当前宽度,`-hNNNdp`指的是 50 | 当前高度。因此,这些会随方向改变而改变。 51 | 52 | ####关于API等级 53 | 54 | -swNNNdp,wNNNdp,以及hNNNdp是在API等级13的时候添加的。因此,较老的设备会忽略所有带有这些限定符的资源。 55 | 56 | 原则上来说,对于那些仍旧支持较老设备的开发者来说,这看起来似乎是个大问题。 57 | 58 | 实际上,这个问题比你所预期的要小,因为那些较老设备中的大部分是手机,而不是平板。 59 | 60 | Android2.x 平板中有明显销量的只有三个7“的型号: 61 | 62 | * 初代的`Kindle Fire` 63 | * 初代的`Barnes&Noble NOOK`系列 64 | * 初代的`Samsung Galaxy Tab` 65 | 66 | 它们中,只有`Galaxy table`有那时的`Android Market`(现在的`Play Store`), 67 | 你可以仅仅忽略API等级13之前的平板就可以了。使用`-swNNNdp`来为较大设备创建 68 | 分隔线,`Galaxy table`只不过会使用你用于较小设备的布局。 69 | 70 | 如果这个令你担忧,或者你也想支持`Kindle Fire`和早期的`NOOK`,你可以使用 71 | 布局别名来最小化代码重复。例如,假定你想要有针对不同版本的手机和平板的res/layout/main.xml 72 | 文件,并且你想要就像平板布局习惯的那样使用-swNNNdp作为你的分隔线。但是你想要支持较老的平板, 73 | 就像`Galaxy Tab`,使用以下的方法: 74 | 75 | * 把你平板大小的布局放进res/layout/中,但是用的是不同的文件名(例如,res/layout/main_to_be_used_for_tablets.xml) 76 | * 在res/values-swNNNdp/layouts.xml,对于你的选择的NNN值,把用于原本名称的别名(通过name属性)指向 77 | 你想用作-swNNNdp设备的资源。 78 | 79 | 80 | @layout/main_to_be_used_for_tablets 81 | 82 | 83 | * 在res/values-larget/layouts.xml,放入这些相同的别名 84 | 85 | 现在,当引用相同的资源名的时候,较老和较新的设备都会路由到用于它们屏幕大小的正确布局。 86 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/StateSavingScenarios.md: -------------------------------------------------------------------------------- 1 | ###状态保存的多个场景 2 | 3 | 当用户旋转屏幕,或者把设备放到汽车充电底座,或者改变设备的语言,你的进程是没有被终止的。默认 4 | 情况下,activity会连同你的控件和fragment一起重建-但是进程依然坚挺。 5 | 6 | 但是,有很多种情况下当你的到后台之后你的进程会被终止。这是由Android自动或者用户手动完成的。 7 | 8 | 取决于你进程终止方式的不同,存在多种方法能让用户在返回到你的应用时期待应用和他们离开时一样。 9 | 例如,假如用户在你的应用中,然后按下HOME键把你的应用移动到后台。几个小时过去了, 10 | Android终止了你的应用释放内存给其它应用。在这之后的某个时间,用户唤起最近任务列表然后 11 | 在列表中点击了你的应用。从用户的角度来说,他们应该返回到与当他们按下HOME键时相同的状态。 12 | 但是如果你的进程被终止了,默认情况下你会丢失所有的状态。 13 | 14 | 有一些用于处理配置改变的技术-它们包括“保存的实例状态Bundle”-也会帮助你处理最近任务列表的场景。 15 | 一些其它技巧-例如保留fragment-只会对配置改变的处理有帮助,但就最近任务列表场景来说不会做任何 16 | 事情。因此,通常的经验做法是在你能使用Bundle的地方就使用Bundle,在Bundle不适合或不能胜任的地方使用 17 | 其他技术(例如,保存了的fragment)。 18 | 19 | 但是,记住所有这些状态是为临时数据而设计的,用户不在意的数据永远不会被再次看到。例如,假定用户在 20 | 你的应用中,然后按下HOME键把你的应用移动到后台。几个小时过去了,由于用户一直在使用它们的设备,你 21 | 掉落了最近任务列表,因为这个列表不会无限扩展。此例中,如果用户再次启动了你的应用(通过主屏幕的启动图标), 22 | 你不可能重新获取任何状态信息进行使用。用户填充到旧的应用实例的数据,其中的数据一定要被记住并且将来要在 23 | 你的应用中重新使用的,需要你自己进行持久化到数据库或者其它类型的文件中。 24 | 25 | 记住了所有这些,让我们分析下用于处理临时状态的选项,这个分析会注重于配置改变。 26 | -------------------------------------------------------------------------------- /ResourceSetsandConfigurations/What'saConfigurationAndHowDoTheyChange.md: -------------------------------------------------------------------------------- 1 | ###什么是配置?以及它们是如何修改的? 2 | 3 | Android硬件的不同部分可以有不同的特性,例如: 4 | 5 | * 不同屏幕尺寸 6 | * 不同屏幕密度 7 | * 不同数量和功能的相机 8 | * 不同无线电的混合(GSM?CDMA?GPS?Bluetooth?WiFi?NFC?一些其它的?) 9 | * 等等 10 | 11 | 其中的一些,在Android核心小组的眼中,可能驱动像布局和“drawable”资源的选择。 12 | 不同屏幕尺寸可能驱动布局的选择。不同屏幕密度可能驱动`drawable`的选择(在 13 | 较高密度设备上使用较高分辨率的图片)。这些被认为是设备“配置”的一部分。 14 | 15 | 其它没有驱动资源选择的不同——不是设备的配置的一部分,而仅仅是一些设备有 16 | 而其它设备没有的特性。例如,相机、蓝牙以及WiFi就是特性。 17 | 18 | 部分配置只会因设备的不同而变化。例如在运行的时候,屏幕密度不会变。但是部分配置,可以在设备的操作 19 | 期间被改变,例如方向(纵向vs.横向)或者语言。当一个配置切换成其它东西的时候,这就是一个配置修改。 20 | 为了帮助开发者调整他们的应用来匹配新的配置,Android针对此类的事件提供了特定的支持。 21 | -------------------------------------------------------------------------------- /ServicesandtheCommandPattern/README.md: -------------------------------------------------------------------------------- 1 | ###`Service`和命令模式 2 | -------------------------------------------------------------------------------- /SomeWordsAboutResource/Dimensions.md: -------------------------------------------------------------------------------- 1 | ###尺寸 2 | 3 | 尺寸被用于Android中的很多地方来描述距离,例如一个控件的大小。有很多不同的度量单位可供你选择: 4 | 5 | 1. px意味着设备像素,因为不是所有的设备的屏幕密度都是一样的,所以大小会因设备而变化。 6 | 7 | 2. 基于屏幕实际尺寸的,分别代表英寸和毫米的in和mm 8 | 9 | 3. pt代表点,一英寸的1/72(再一次是基于实际的屏幕尺寸的) 10 | 11 | 4. dip(或dp)代表密度独立像素-在大约160dpi分辨率的屏幕上一个dip等于1个像素, 12 | 但是在大约320dpi的屏幕上一个dip等于两个设备像素。 13 | 14 | 5. sp代表缩放的像素,对于正常字体缩放等级来说一个sp等于一个dip。 15 | 因设置中选择的字体缩放等级进行增大或缩小。 16 | 17 | 尺寸资源默认是存放在同时也存放你字符串的res/values/目录下的dimens.xml文件中的。 18 | 19 | 为了把一个尺寸编码成资源,添加一个dimen元素到dimens.xml文件中,元素中带有这个字眼的唯一标识名,以及代表值的单个子text元素: 20 | 21 | 22 | 10dip 23 | 1in 24 | 25 | 26 | 在布局中,你可以以@dimen/...的形式引用尺寸,省略号是资源的唯一标识名(例如,以上的thin 27 | 和fat)。在Java中,你可以以带有R.dimen前缀的唯一名称来引用尺寸资源(例如, 28 | Resource.getDimension(R.dimen.thin))。 29 | 30 | 虽然我们的存根项目不是用尺寸资源,但是我们不久就会看到了。 31 | 32 | ####编辑尺寸文件 33 | 34 | 和大部分XML资源一样,当你在项目浏览器中双击资源,Android Studio就会让你直接编辑XML. 35 | -------------------------------------------------------------------------------- /SomeWordsAboutResource/GotthePicture.md: -------------------------------------------------------------------------------- 1 | ###有图片? 2 | 3 | Android支持PNG,JPEG以及GIF的图片格式。GIF官方是不鼓励使用的,然而,是总的来说可取的格式。 4 | Android也支持一些基于XML的专有图片格式,尽管在书的后面才会讨论到那个深度。 5 | 6 | 默认给这些所谓drawable资源的目录是res/drawable/。所有在那找到的图片可以从Java代码或其它地方(例如manifest)引用到,无关设备特性。 7 | 8 | 但是,你的存根目录并没有一个res/drawable/目录。 9 | 10 | 取而代之的,它有着像res/drawable-mdpi和res/drawable-hdpi这样的目录。 11 | 12 | 它们涉及到不同的资源集。后缀(例如,-mdpi,hdpi)是过滤器,指示在什么情形喜爱存储在这些目录中的图片应该被使用。 13 | 具体的,-ldpi指示图片指示图片应该在有着低密度的屏幕(大约每英寸120个像素点,dpi)的设置上使用。 14 | -mdpi后缀指示资源适用于中等密度屏幕的(大约160dpi),-hdpi指示资源是用于高密度屏幕的(大约240dpi)。 15 | -xhdpi指示资源是用于超高密度屏幕的(大约320dpi),-xxhdp指示用于超超高密度屏幕(大约480dpi), 16 | -xxxhdpi指示用于超超超高密度屏幕(大约640dpi),等等。 17 | 18 | 19 | 在每个这些目录中,你会看到一个ic_launcher.png文件(可能还有其它图标)。这是被你的应用用于显示在主界面应用启动器上的固有图标。 20 | 每个图片都是相同的图标,但是高密度的图标有着更多的像素。目标是在每个设别上图片看起来差不多同个尺寸,使用较高密度的有着 21 | 更详细的图片。 22 | 23 | 例如,我们的EmPubLite教程项目有着像res/drawable-hdpi/,res/drawable-xhdpi/,以及 24 | res/drawable-mdpi/的目录。每个可以包含为密度定制的固有启动图标(ic_launcher.png)。 25 | 26 | 我们的AndroidManifest.xml文件然后在元素中引用了我们的icon_launcher图标: 27 | 28 | 29 | 33 | 34 | 39 | 42 | 43 | 48 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 注意,manifest仅仅引用了@drawable/icon_launcher,来告诉Android找到一个叫做 61 | ic_launcher的drawable资源。资源文件引用并没有指示文件的资源类型-在资源标识中没有.png。 62 | 这就意味着ic_launcher.png和ic_launcher.jpg不能在同一个项目中,因为它们以相同的标识符 63 | 识别。你需要保持“基本名"(文件名没有扩展)在所有你的图片中是唯一的。 64 | 65 | 同样的,@drawable/ic_launcher引用并没有提及到使用什么屏幕尺寸。那是因为Android会基于运行你 66 | 应用的设备选择要使用的正确屏幕密度。你不需要明确担心从你的多个图标拷贝中去选。 67 | 68 | ####额....但我有的是“Mipmaps"? 69 | 70 | 如果你通过Android Studio的新项目向导创建了一个项目,结果是项目中不会有关于res/drawables-*/的目录, 71 | 而是mipmap目录(例如,res/mipmap-hdpi/)。 72 | 73 | 这几乎是没有文档化的。实际上,它们都是drawables,只不过是一个以@mipmap/..而不是@drawable/...引用。 74 | 75 | 对于大都数drawables来说,把它们放进res/drawable-*/目录,即使你不得不自己来创建它们。 76 | 77 | 78 | ####获取Android Drawables 79 | 80 | 你可能是一个平面设计师。或者,你可能认识一位平面设计师。在这些情形中,你可以 81 | 创建你自己的icons,理想情况下遵循Google的[图标设计指导](https://www.google.com/design/spec/style/icons.html)。 82 | 83 | 如果你不是一个平面设计师并且没有接触到一个,你需要以其它方式来获取你的drawable。有很多来自 84 | 第三方的图标库,但是以下章节略述了一些Google的用于把图标放进你应用的解决方案。 85 | 86 | 87 | #####Android 图标设置向导 88 | 89 | Android Studio和Eclipse都提供了一个图标设置向导。这个向导是为了获取一张启动图片然后给予你用于某个图片职责的多个密度图标而设计的, 90 | 例如你的启动图标(我们早前在这章看到的ic_launcher文件)。 91 | 92 | 在Eclipse上,图标设置向导会给你drawable资源。在AndroidStudio上,如果你选择创建启动图标的话,图标设置向导会给你 93 | mipmap资源,如果你选择其它类型图标,它会给你drawable资源。 94 | 95 | #####`Android Asset` 工作室 96 | 97 | 图标设置向导的功能可以存在于集成开发环境之外(在一个Chrome浏览器中)以[`Android Asset`工作室]的形式。有了 98 | 这个图标设置向导,你就可以选择一个图标类型了(例如,启动图标): 99 | 100 | 然后你可以指定基本图片的来源(上传的文件,剪贴画或自由形式的文本)和其它配置数据。产生的多个密度的图片,可以从页面底部进行下载。 101 | 102 | #####编辑已经存在的drawable资源 103 | 104 | 不管Android Studio还是Eclipse都没有用于PNG和JPEG文件的图片编辑器。因此,你会在集成开发环境之外进行这些图片的编辑。 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /SomeWordsAboutResource/README.md: -------------------------------------------------------------------------------- 1 | ##一些关于资源的话 2 | 3 | 在这个时间点你很有可能已经迫不及待地开始真正写一些代码了。这是可以理解的。尽管如此,在我们深入到我们存根项目的Java源代码之前,我们真的 4 | 需要简短地聊聊资源。 5 | 6 | 资源是少量静态的存放在Java源代码之外的信息。资源以文件形式存放在你Android项目layout目录下的res/目录下。 7 | 在这里,你可以找到你所有的图标和其它的图片,用于国际化的外部化字符串,等等。 8 | 9 | 它们和Java源代码分开的原因不仅是因为它们格式上不同。把它们分开是因为你可以在不同情形下有多个资源的定义。 10 | 例如,国际化的时候,你需要用于不同语言的字符串。你的Java代码还是很大程度上能够不在意这个的,因为Android会在给定情形下,从所有 11 | 备选的中,选择使用正确的资源(例如,如果设备的地点被设置成西班牙就选择西班牙语字符串)。 12 | 13 | 我们会在这本书稍后的内容中涵盖所有这些资源集的细节。现在,我们需要加上一个关于在我们存根项目中使用的资源的讨论。 14 | 15 | 16 | 这章会提及到res/目录。Android Studio用户会在它们的app/src/main/目录下发现这个。 17 | 18 | -------------------------------------------------------------------------------- /SomeWordsAboutResource/StringTheory.md: -------------------------------------------------------------------------------- 1 | ###字符串理论 2 | 3 | 把你的标签和其它文本保存在你应用的main源代码之外,通常被认为是一个好主意。特别地,它对于国际化(I18N)和本地化(L10N)是有帮助的。 4 | 即使你不会要吧你的字符串翻译成其它语言,如果所有的字符串在一个地方比分布在你的源代码中改起来会比较容易。 5 | 6 | ####明文字符串 7 | 8 | 通常来讲,所有你需要的是在res/values目录中放一个XML文件(通常命名成res/values/strings.xml),其中有一个resource根元素以及 9 | 一个子string元素用于你想要编码成资源的每个字符串。string元素有一个name属性,这个属性是这个字符串的唯一标识符,以及单个包含字符串文本的 10 | text元素: 11 | 12 | 13 | The quickbrown fox... 14 | He who laughs lat... 15 | 16 | 17 | 一个棘手的部分是如果字符串的值包含了一个引号或一个所有格符号。在这些情形中,你会想要以在它们之前加反斜线来转义这些值 18 | (例如,There are the times that try men\'s souls)。或者,如果它仅仅是个所有格符号,你可以吧这个值装入引号 19 | (例如,“These are the times that try men's souls.")。 20 | 21 | 例如,一个项目的strings.xml文件可以像这个一样: 22 | 23 | 24 | 25 | 26 | EmpubLite 27 | Hello world! 28 | 29 | 30 | 31 | 我们可以从我们Java源代码和其它多个地方引用这些字符串资源。例如,app_name字符串资源经常在AndroidManifest.xml文件中被使用: 32 | 33 | 34 | 44 | 48 | 50 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 这里,元素中的android:label属性引用了app_name字符串资源。这个会出现在应用程序的几个地方, 60 | 尤其是设置中的已安装程序列表。所以,如果你想要改变你应用名如何在这些地方显现,只要挑战app_name字符串资源就能满足。 61 | 62 | @string/app_name语句告诉Android"找到叫做app_name的字符串资源"。这导致Android扫描合适的strings.xml文件(或你的res/values/目录下其它 63 | 包含字符串资源的文件)来尝试找到app_name。 64 | 65 | ####样式文本 66 | 67 | 许多Android中的东西可以显示富文本,其中文本使用一些轻量化的HTML标记:,和进行了格式化处理。 68 | 你的字符串资源仅仅以你在网页中使用HTML标签的方式支持了这个。 69 | 70 | 71 | This hasboldin it. 72 | Whereas this has italics! 73 | 74 | 75 | 76 | CDATA.CDATA 跑起来。跑起来,DATA,跑起来 77 | 78 | 因为字符串串资源文件是一个XML文件,如果你的信息中包好了<,>或&字符(以及上述列出的格式化标签), 79 | 你会需要使用一个`CDATA section`: 80 | 81 | 82 | 84 | 85 | TPS Report for :{{reportDate}} 86 | Here are the contents of the TPS report: 87 | {{message}} 88 | If you have any questions reguarding this report,please 89 | do not ask Mark Murphy. 90 | 91 |
Here are the contents of the TPS report:
{{message}}
If you have any questions reguarding this report,please 89 | do not ask Mark Murphy.