Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin in production

GDG SPb
March 15, 2017

Kotlin in production

Видео: https://youtu.be/Fe_eF1Jd0LA

В феврале 2016 года состоялся релиз первой версии языка Kotlin. Вокруг этого события поднялось большое количество хайпа среди Android-разработчиков. Многие стали пробовать писать на Kotlin Android-приложения. Весь синтаксический сахар, поддержка иммутабельности, null-safety, extension функции и многое другое выглядело весьма соблазнительно на фоне Java 7. В компании Aviasales тоже не могли пройти мимо данного релиза. Евгений расскажет про тернистый путь миграции крупного продакшн проекта на Kotlin и как теперь с этим живется.

Автор: Евгений Шишкин

Android-разработчик с опытом более 6 лет. Адаптировал телефоны LG под российский рынок, разрабатывал умного ассистента в i-Free и амбициозный аудиогид izi.TRAVEL. В 2016 году присоединился к команде Aviasales, где разрабатывает приложение Hotellook для поиска лучших цен на отели. Есть собственные open-source проекты (RobotoTextView, AppMsg, ProgressFragment и т.д.).

GDG SPb

March 15, 2017
Tweet

More Decks by GDG SPb

Other Decks in Technology

Transcript

  1. NPE

  2. class MapFragment : Fragment() {
 private lateinit var mapView: MapView


    
 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
 mapView = MapView(context)
 return mapView
 }
 
 override fun onDestroyView() {
 super.onDestroyView()
 mapView = null
 } }
  3. var destination: String? = "New York"
 
 fun setDestinationInUpperCase() {


    if (destination != null) {
 destinationView.text = destination.toUpperCase()
 }
 }
  4. class HotelPanoramaViewFragment extends Fragment { private static final int STREET_VIEW_RADIUS

    = 150 …
 
 void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
 super.onStreetViewPanoramaReady(panorama);
 panorama.setPosition(hotelLocation, STREET_VIEW_RADIUS);
 } }
  5. class HotelPanoramaViewFragment : Fragment() { …
 
 override fun onStreetViewPanoramaReady(panorama:

    StreetViewPanorama) {
 super.onStreetViewPanoramaReady(panorama)
 panorama.setPosition(hotelLocation, STREET_VIEW_RADIUS)
 } 
 private companion object {
 const val STREET_VIEW_RADIUS = 150 }
 }
  6. public abstract class MonkeySafeClickListener implements View.OnClickListener {
 
 @Override
 public

    void onClick(View v) {
 if (AndroidUtils.preventDoubleClick()) {
 Timber.d("Click prevented");
 return;
 }
 onSafeClick(v);
 }
 
 public abstract void onSafeClick(View v);
 }
  7. inline fun View.onSafeClick(crossinline clickListener: (v: View) -> Unit) {
 setOnClickListener(object

    : MonkeySafeClickListener() {
 override fun onSafeClick(v: View) = clickListener(v)
 })
 }
  8. public class SearchFormFragment extends Fragment {
 @BindView(R.id.destination) EditText destinationView;
 private

    Unbinder unbinder;
 
 @Nullable
 @Override
 public View onCreateView(LayoutInflater inflater,
 @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 return inflater.inflate(R.layout.fragment_search_form, container, false);
 }
 
 @Override
 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
 unbinder = ButterKnife.bind(this, view);
 // ...
 }
 
 @Override
 public void onDestroyView() {
 super.onDestroyView();
 unbinder.unbind();
 }
 
 @OnClick(R.id.apply)
 public void apply() {
 String destination = destinationView.getText().toString();
 // ...
 }
 }
  9. class SearchFormFragment : Fragment() {
 @BindView(R.id.destination) internal var destinationView: EditText?

    = null
 private var unbinder: Unbinder? = null
 
 override fun onCreateView(inflater: LayoutInflater?,
 container: ViewGroup?, savedInstanceState: Bundle?): View? {
 return inflater!!.inflate(R.layout.fragment_search_form, container, false)
 }
 
 override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
 unbinder = ButterKnife.bind(this, view!!)
 // ...
 }
 
 override fun onDestroyView() {
 super.onDestroyView()
 unbinder!!.unbind()
 }
 
 @OnClick(R.id.apply)
 fun apply() {
 val destination = destinationView!!.text.toString()
 // ...
 }
 }
  10. !!

  11. override fun onCreateView(inflater: LayoutInflater?,
 container: ViewGroup?, savedInstanceState: Bundle?): View? {


    return inflater!!.inflate(R.layout.fragment_search_form, container, false)
 }
  12. @Nullable
 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle

    savedInstanceState) {
 return null;
 } https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/Fragment.java
  13. override fun onCreateView(inflater: LayoutInflater,
 container: ViewGroup?, savedInstanceState: Bundle?): View? {


    return inflater.inflate(R.layout.fragment_search_form, container, false)
 }
  14. open class BaseFragment : Fragment() {
 
 override fun onActivityResult(requestCode:

    Int, resultCode: Int, data: Intent) {
 super.onActivityResult(requestCode, resultCode, data)
 }
 
 override fun onAttach(context: Context) {
 super.onAttach(context)
 }
 
 override fun onAttachFragment(childFragment: Fragment) {
 super.onAttachFragment(childFragment)
 }
 
 override fun onConfigurationChanged(newConfig: Configuration) {
 super.onConfigurationChanged(newConfig)
 }
 
 override fun onContextItemSelected(item: MenuItem): Boolean {
 return super.onContextItemSelected(item)
 }
 
 override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo) {
 super.onCreateContextMenu(menu, v, menuInfo)
 }
 
 override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
 super.onCreateOptionsMenu(menu, inflater)
 }
 
 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
 return super.onCreateView(inflater, container, savedInstanceState)
 }
 
 override fun onOptionsItemSelected(item: MenuItem): Boolean {
 return super.onOptionsItemSelected(item)
 }
 
 override fun onOptionsMenuClosed(menu: Menu) {
 super.onOptionsMenuClosed(menu)
 }
 
 override fun onPrepareOptionsMenu(menu: Menu) {
 super.onPrepareOptionsMenu(menu)
 }
 
 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
 super.onRequestPermissionsResult(requestCode, permissions, grantResults)
 }
 
 override fun onSaveInstanceState(outState: Bundle) {
 super.onSaveInstanceState(outState)
 }
 
 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 super.onViewCreated(view, savedInstanceState)
 }
 }
  15. class SearchFragment : Fragment() {
 @BindView(R.id.destination) lateinit var destinationView: EditText


    private lateinit var unbinder: Unbinder
 
 override fun onCreateView(inflater: LayoutInflater,
 container: ViewGroup?, savedInstanceState: Bundle?): View? {
 return inflater.inflate(R.layout.fragment_search_form, container, false)
 }
 
 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 unbinder = ButterKnife.bind(this, view)
 // ...
 }
 
 override fun onDestroyView() {
 super.onDestroyView()
 unbinder.unbind()
 }
 
 @OnClick(R.id.apply)
 fun apply() {
 val destination = destinationView.text.toString()
 // ...
 }
 }
  16. v1.0 v1.0.6 v1.1.0 300 KB 600 KB 900 KB 1200

    KB DEX size http://www.methodscount.com/
  17. import kotlinx.android.synthetic.main.fragment_search_form.*
 
 class SearchFragment : Fragment() {
 
 


    fun apply() {
 val destination = destinationView.text.toString()
 // ...
 }
 }
  18. Q&A