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

Introduction to Android Development

Introduction to Android Development

The basics, best practices and the future of Android development

Sérgio Santos

April 06, 2016
Tweet

More Decks by Sérgio Santos

Other Decks in Programming

Transcript

  1. Overview • Basics • Architecture • Level 1 - Databases,

    APIs, Compatibility • Level 2 - Testing, Dependency Injection • Future
  2. Activities (code) public class HomeActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); } }
  3. Activities (intents) Intent intent = new Intent(this, HomeActivity.class); startActivity(intent); Uri

    browerUri = Uri.parse("http://www.google.com"); Intent browserIntent = new Intent(Intent.ACTION_VIEW, browerUri); startActivity(browserIntent);
  4. Application Manifest <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.bloco.intro"> <uses-permission android:name="android.permission.INTERNET"/>

    <!-- Rest of permissions --> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name"> <activity android:name=".HomeActivity" android:label="@string/home"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".AnotherActivity" android:label="@string/another"> <!-- Rest of activities --> </manifest>
  5. Application Build apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion

    "23.2.1" defaultConfig { minSdkVersion 17 targetSdkVersion 23 versionCode 1 versionName "1.0" } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.2.1' // Rest of dependencies }
  6. Using resources public class HomeActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); Button sendButton = (Button) findViewById(R.id.send); EditText messageEditText = (EditText) findViewById(R.id.message); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String message = messageEditText.getText(); Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } }); } }
  7. Custom Views <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <io.bloco.intro.AwesomeEditText android:id="@+id/message" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:hint="@string/message" /> <Button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/send" /> </LinearLayout>
  8. Custom Views class AwesomeEditText extends EditText { public AwesomeEditText(Context context,

    AttributeSet attrs) { super(context, attrs); } @Override public Editable getText() { return super.getText().append(" (awesome!)"); } }
  9. Data binding <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="io.bloco.intro.User"/> </data> <LinearLayout

    android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </LinearLayout> </layout>
  10. Data binding @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); HomeActivityBinding

    binding = DataBindingUtil.setContentView(this,R.layout.activity_home); User user = new User("Sérgio", "Santos"); binding.setUser(user); }
  11. Content Providers // Run query Cursor cur = null; ContentResolver

    cr = getContentResolver(); Uri uri = Calendars.CONTENT_URI; String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND (" + Calendars.ACCOUNT_TYPE + " = ?) AND (" + Calendars.OWNER_ACCOUNT + " = ?))"; String[] selectionArgs = new String[] {"[email protected]", "com.google", "[email protected]"}; // Submit the query and get a Cursor object back. cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
  12. Realm Realm realm = Realm.getInstance(this); // All writes are wrapped

    in a transaction to facilitate safe multi threading realm.beginTransaction(); // Add a person Person person = realm.createObject(Person.class); person.setName("Young Person"); person.setAge(14); realm.commitTransaction(); RealmResults<User> result = realm.where(User.class) .greaterThan("age", 10) // implicit AND .beginGroup() .equalTo("name", "Peter") .or() .contains("name", "Jo") .endGroup() .findAll();
  13. Retrofit public interface TwitterService { @GET("timeline/{userId}") Call<List<Tweet>> listTweets(@Path("userId") String userId);

    } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.twitter.com/") .build(); TwitterService twitterService = retrofit.create(TwitterService.class);
  14. Retrofit twitterService .listTweets("sdsantos" ) .enqueue(new Callback<List<Tweet>> { @Override public void

    onSuccess(Call<List<Tweet>> call, Response<List<Tweet>> response) { List<Tweet> tweets = request.body(); // Do something with tweets } @Override public void onError(ApiError apiError) { // Show error } });
  15. Instrumentation Testing with Espresso @RunWith(AndroidJUnit4.class) public class CalculatorActivityTest { @Rule

    public ActivityTestRule<CalculatorActivity> activityTestRule = new ActivityTestRule<>(CalculatorActivity.class); @Test public void testSum() throws Exception { onView(withId(R.id.calculator_input)) .perform(typeText("2 + 2")) onView(withText("=")) .perform(click()); onView(withId(R.id.calculator_result)) .check(matches(withText("4"))); } }
  16. Unit Testing with Mockito class Controller { private final Database

    database; private final Screen screen; public Controller(Database database, Screen screen) { this.database = database; this.screen = screen; } public void check() { List<String> fruits = database.getFruits(); if (fruits.isEmpty()) { screen.showEmptyMessage(); } else { screen.showFruits(fruits); } } }
  17. Unit Testing with Mockito public class ControllerTest extends AndroidTestCase {

    private Controller controller; private Database database; private Screen screen; @Override protected void setUp() throws Exception { super.setUp(); database = mock(Database.class); screen = mock(Screen.class); controller = new Controller(database, screen); } // Tests... } // Tests public void testCheckWithFruit() { List<String> fruits = new ArrayList<>(); fruits.add("banana"); fruits.add("apple"); when(database.getFruits()).thenReturn(fruits); controller.check(); verify(screen).showFruits(eq(fruits)); } public void testCheckEmpty() { List<String> emptyFruits = new ArrayList<>(); when(database.getFruits()).thenReturn(emptyFruits); controller.check(); verify(screen).showEmptyMessage(); }
  18. Dependencies // Avoid class Foo { public Foo() { Bar

    bar = new Bar(); // or Bar.getInstance() bar.something(); } } new Foo(); // Better class Foo { public Foo(Bar bar) { bar.something(); } } new Foo(new Bar());
  19. Dependencies // Perfect interface Bar { void something() } class

    MyBar implements Bar { @Override public void something() { // ... } } class Foo { public Foo(Bar bar) { bar.something(); } } new Foo(new MyBar());
  20. Dependency Injection // Goal class Foo { @Inject public Foo(Bar

    bar) { bar.something(); } } Dagger v1: http://square.github.io/dagger/ Dagger v2: http://google.github.io/dagger/
  21. Resources • Google Codelabs: https://codelabs.developers.google.com • Android development like a

    pro: https://speakerdeck.com/rallat/android-development-like-a-pro • Fernando Cejas: http://fernandocejas.com • Kotlin 101: https://speakerdeck.com/ivanbruel/kotlin-101 • Bloco’s blog: https://bloco.io/blog