Upload
keiji-ariyama
View
1.210
Download
3
Embed Size (px)
Citation preview
C-LIS CO., LTD.
自己紹介
Android Studio本
3
2014年11月21日発売
技術評論社刊
Android Studio 0.8.6http://amzn.to/1HYRp32
4
5
改訂版が出ます(2016年1月上旬)
改訂版の原稿を送ったのが11月16日
7
11月20日
8
Android Studio 1.5 Release
続く
2015年のAndroidアプリ開発入門
ABCD 2015 Kanazawa
2015/11/22 石川工業高等専門学校
ターゲット
11
Android 2.x系からのAndroidアプリ開発者
これからAndroidアプリ開発を学ぼうとしている初心者
2015年のAndroid
Androidのバージョン
13
2.3GingerBread
3.xHoneycomb
4.0
IceCreamSandwich
Androidのバージョン
14
4.1/4.2/4.3
Jelly Bean
4.4
KitKat
Androidのバージョン
15
5.0
Lollipop
6.0
Marshmallow
バージョンの分布
16https://developer.android.com/intl/ja/about/dashboards/index.html
プラットフォームの拡大
17
TV Auto
プラットフォームの拡大
18
Wearable
API Level
API Level
20
バージョン API Level バージョンコード
6.0 23 M
5.1 22 Lollipop_MR1
5.0 21 Lollipop
4.4W 20 KitKat for Wearables Only
4.4 19 KITKAT
4.3 18 JELLY_BEAN_MR2
4.2 - 4.2.2 17 JELLY_BEAN_MR1
4.1 - 4.1.1 16 JELLY_BEAN
API Level
21
バージョン API Level バージョンコード
4.0.3, 4.0.4 15 ICE_CREAM_SANDWICH_MR1
4.0, 4.0.1, 4.0.2 14 ICE_CREAM_SANDWICH
3.2 13 HONEYCOMB_MR2
3.1.x 12 HONEYCOMB_MR1
3.0.x 11 HONEYCOMB
2.3.3, 2.3.4 10 GINGERBREAD_MR1
2.3 - 2.3.2 9 GINGERBREAD
Fragment
Activity
23
Activity
24
Activity
• 1つの画面を構成する
• Androidのシステムコンポーネントの一つ(Activity/Service/BroadcastReceiver/ContentProvider) • AndroidManifest.xmlに記載する
• 他のアプリから呼び出すことができる
IntentFilter
タブレットの登場(Android 3.0)
25
Fragment
26
• 1つの画面(Activity)を分割する
• システムコンポーネントではない
= AndroidManifest.xmlに記載の必要なし
• 他のアプリから呼び出すことができない
Fragmentの例
27
Android 3.0(API Level 11)未満
28
Fragmentは使えない
Support Libraries
29
http://developer.android.com/intl/ja/tools/support-library/index.html
• バージョンやプラットフォームの差を埋める互換(Compat)クラスを含む
• android.support.v4.app は、API Level 4以降に対応するv4 Support Library
v7 Support Libraries
v13 Support Library
v14 Preference Support Library
v17 Preference Support Library for TV
v17 Leaseback Library
Design Support Library
Fragmentを使うには
30
com.android.support-v4 ライブラリー
public class MainActivity extends AppCompatActivity { public static final int REQUEST_CODE = 0x1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); ab.setIcon(R.mipmap.ic_launcher); getSupportFragmentManager() .beginTransaction() .add(R.id.content, SettingFragment.newInstance(), SettingFragment.class.getSimpleName()) .commit(); }}
Fragmentを使うには
public class SettingFragment extends Fragment {
}
Fragmentを使うには
android.support.v4.app.Fragment
android.app.Fragment
どちらのパッケージを使う?
android.support.v4.app.Fragment android.app.Fragment
バージョンの分布
34https://developer.android.com/intl/ja/about/dashboards/index.html
ViewPager
35
android.support.v4.view.ViewPager
36
http://developer.android.com/intl/ja/reference/android/support/v4/view/ViewPager.html
android.support.v4.app.Fragment android.app.Fragment
最近のAndroidでは……
37
Google Maps
39
Google Map API
40
https://code.google.com/intl/ja/android/maps-api-signup.html
Google Maps v2 API
42
Google Play Services
43
Google Play Services
44
• Google Adwords
• Google Fit
• Play Games API
• Location API
• Panorama API
• NearBy
• Google Plus
• Vision (顔認識・バーコード認識)
• Google Wallet
• Wearable
プラットフォームの拡大
45
Amazon Kindle Fire
Androidベースのプラットフォーム
Google Play Store無し
= Androidのエコシステムに入らない
UI / UX
さよならMenu Button
47
Say Goodbye to the Menu Button http://android-developers.blogspot.jp/2012/01/say-goodbye-to-menu-button.html
Menu Button → ActionBar
48
NavigationDrawer
49
ActionBar → ToolBar
50
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/main_content" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent"/></LinearLayout>
ActionBar → ToolBar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="colorPrimary">@color/primary</item> <item name="colorPrimaryDark">@color/primary_dark</item> <item name="colorAccent">@color/accent</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay</item> </style>
ActionBar → ToolBar
ToolBar
ToolBarのタイトルが黒い
Change title color in toolbar?
http://stackoverflow.com/questions/28954586/change-title-color-in-toolbar
54
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/main_content" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="enterAlways|snap" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </android.support.design.widget.AppBarLayout>
AppBarLayout
AppBarLayout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/main_content" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="enterAlways|snap" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </android.support.design.widget.AppBarLayout>
AppBarLayout
Design Support Library
58
Google I/O 2015で発表
画面デザインに特化したサポートライブラリー
https://github.com/chrisbanes/cheesesquare
Cheesesquare
59
Material Design
60
https://www.google.com/design/spec/material-design/introduction.html
FAB
61
Floating Action Button
Floating Action Button
62
Material Color
63
Primary Color
Accent Color
開発環境
65
Android Developer Tools
Android Studio
Android Developer Tools
66
Eclipse+プラグイン 2007年から標準の開発環境
2015年12月末でサポート終了を発表
An update on Eclipse Android Developer Tools http://android-developers.blogspot.jp/2015/06/an-update-on-eclipse-android-developer.html
Android Studio
67
Google I/O 2013で発表
2015年にバージョン1.0がリリース
チェコJetBRAINS社が開発している
「IntelliJ IDEA Community Edition」
がベース
ビルドシステムは「Grade」
Android plugin for Gradle でAndroid
アプリのビルドに対応している
Android Studio本
68
2014年11月21日発売
技術評論社刊
Android Studio 0.8.6http://amzn.to/1HYRp32
69
70
http://amzn.to/
改訂版が出ます(2016年1月上旬)
改訂版の原稿を送ったのが11月16日
72
11月20日
73
Android Studio 1.5 Release
続き
Android Studio Update Checker
75
Android Studio Update Checker
76
•Support V7 Library AppCompat Preference
•Design Support Library
各バージョンでの見た目
77
各バージョンでの見た目
78
Notification(通知)
重要度 種別
80
プライベートな通知を非表示に
81
NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setContentTitle(context.getText(R.string.new_android_studio)) .setContentText(context.getText(R.string.new_android_studio_version_available)) .setTicker(context.getText(R.string.new_android_studio_version_available)) .setPriority(NotificationCompat.PRIORITY_MAX) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.mipmap.ic_launcher) .setDefaults(Notification.DEFAULT_VIBRATE);NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(builder) .setBigContentTitle(context.getText(R.string.new_android_studio_version_available));for (UpdateState.Product.Channel channel : updatedChannelList) { UpdateState.Product.Channel.Build build = channel.builds.get(0); inboxStyle.addLine(String.format(Locale.US, "%s in %s channel.\n", build.version, channel.status));} NotificationManager nm = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);nm.notify(NOTIFICATION_ID, builder.build());
NotificationCompat(support.v4)
82
NotificationCompat
83
Android Wear
84
NotificationCompat
85
java.lang.IllegalArgumentException: contentIntent required:
pkg=io.keiji.asupdatechecker
id=1
notification=Notification(vibrate=default,sound=null,defaults=0x2,flags=0x80)
Android 2.3
PreferenceFragmentCompat(support.v7)
86http://stackoverflow.com/questions/32070670/preferencefragmentcompat-requires-preferencetheme-to-be-set
Product Flavors
87
supportedFlavor Support Libraryを使ったバージョン
API Level 7以降に対応
latestFlavor Support Libraryを使わないバージョン
API Level 11以降に対応
https://github.com/keiji/AsUpdateChecker
Demo
まとめ
89
ViewPagerを使う場合はSupport Library 一択
ただし、PreferenceFragmentを使う場合は通常の
Fragmentがお勧め
その場合、個別のActivityとしてSupport Library
Fragmentと混合しない。
https://github.com/keiji/AsUpdateChecker
まとめ
90
• Androidはバージョンアップ毎に、さまざまなAPIを追加している。
• 以前のバージョンでも同等機能が使えるように、さまざまなSupport
LibraryがGoogleから提供されている。
• Androidの機能拡張はプラットフォームだけでなく、Google Play開発者
サービスを通じての機能提供も重要度を増している。
• Support Libraryは完全ではない。場合によってはproductFlavorなどを
使ってAPKの分割を検討する必要もある。
C-LIS CO., LTD.
各製品名・ブランド名、会社名などは、一般に各社の商標または登録商標です。 本資料中では、©、®、™を割愛しています。
本資料は、有限会社シーリスの著作物であり、
クリエイティブコモンズの表示-非営利-継承 3.0 Unported ライセンスの元で公開しています。
おまけ
オープンソース・ライブラリー
findViewById
public class MainActivity extends AppCompatActivity { public static final int REQUEST_CODE = 0x1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); ab.setIcon(R.mipmap.ic_launcher); }}
findViewById
public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener { private Button buttonPushMe; private ImageView imageAndroid; private SeekBar seekBarRed; private SeekBar seekBarGreen; private SeekBar seekBarBlue;
ButterKnife
http://jakewharton.github.io/butterknife/
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonPushMe = (Button) findViewById(R.id.btn_pushme); buttonPushMe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { buttonPushMe.setText("ボタンが押されました!"); imageAndroid.setImageResource(R.drawable.droid2); } }); imageAndroid = (ImageView) findViewById(R.id.iv_android); seekBarRed = (SeekBar) findViewById(R.id.sb_red); seekBarRed.setOnSeekBarChangeListener(this); seekBarGreen = (SeekBar) findViewById(R.id.sb_green); seekBarGreen.setOnSeekBarChangeListener(this); seekBarBlue = (SeekBar) findViewById(R.id.sb_blue); seekBarBlue.setOnSeekBarChangeListener(this); }
ButterKnife
http://jakewharton.github.io/butterknife/
public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener { @Bind(R.id.iv_android) ImageView imageAndroid; @Bind(R.id.sb_red) SeekBar seekBarRed; @Bind(R.id.sb_green) SeekBar seekBarGreen; @Bind(R.id.sb_blue) SeekBar seekBarBlue;
ButterKnife
http://jakewharton.github.io/butterknife/
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); seekBarRed.setOnSeekBarChangeListener(this); seekBarGreen.setOnSeekBarChangeListener(this); seekBarBlue.setOnSeekBarChangeListener(this); }
ButterKnife
http://jakewharton.github.io/butterknife/
public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener { @Bind(R.id.btn_pushme) Button buttonPushMe; @OnClick(R.id.btn_pushme) public void onClick(View v) { buttonPushMe.setText("ボタンが押されました!"); imageAndroid.setImageResource(R.drawable.droid2); }
ButterKnife
http://jakewharton.github.io/butterknife/
SQLite ̶ データベース
public class DbHelper extends SQLiteOpenHelper { private static final String DB_NAME = "user-data.db"; private static final int DB_VERSION = 1; public DbHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } private static final String CREATE_USER_TABLE = "CREATE TABLE users (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT," + "gender INTEGER," + "megane INTEGER" + ");"; @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_USER_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }}
SQLite
ContentValues values1 = new ContentValues();values1.put("name", "Claudia Madobe");values1.put("gender", 0); values1.put("megane", 1); ContentValues values2 = new ContentValues();values2.put("name", "Claude Madobe");values2.put("gender", 1); values2.put("megane", 1); SQLiteDatabase db = new DbHelper(this).getWritableDatabase();db.beginTransaction();Log.d(TAG, "id = " + db.insert("users", null, values1));Log.d(TAG, "id = " + db.insert("users", null, values2));db.setTransactionSuccessful();db.endTransaction();Cursor cursor = db.query("users", new String[]{"name", "megane"}, "gender = ? AND megane = ?", new String[]{"0", "1"}, null, null, null);Log.d(TAG, "count = " + cursor.getCount());while (cursor.moveToNext()) { Log.d(TAG, "name = " + cursor.getString(cursor.getColumnIndex("name")));}
SQLite
実行結果 count = 1 name = Claudia Madobe
SQLite
public class User { public static final int GENDER_FEMALE = 0; public static final int GENDER_MALE = 1; private long id; private String name; private int gender = GENDER_FEMALE; private boolean megane = true; public long save(SQLiteDatabase db) { ContentValues values = new ContentValues(); values.put("name", name); values.put("gender", gender); values.put("megane", megane ? 1 : 0); return db.insert("users", null, values); }
// アクセサ省略 }
Userクラス
public class User extends RealmObject { @Ignore public static final int GENDER_FEMALE = 0; @Ignore public static final int GENDER_MALE = 1; private long id; private String name; private int gender = GENDER_FEMALE; private boolean megane = true;
// アクセサ省略 }
Realm
https://realm.io
Realm realm = Realm.getInstance(this); realm.beginTransaction();User user = realm.createObject(User.class); user.setName("Claudia Madobe"); user.setGender(User.GENDER_FEMALE); user.setMegane(true);user = realm.createObject(User.class); user.setName("Claude Madobe"); user.setGender(User.GENDER_MALE);user.setMegane(true);realm.commitTransaction();RealmResults<User> result = realm.where(User.class) .equalTo("gender", User.GENDER_FEMALE) .equalTo("megane", true) .findAll();Log.d(TAG, "count = " + result.size());for (User userData : result) { Log.d(TAG, "name = " + userData.getName());}
Realm
https://realm.io
実行結果 count = 1 name = Claudia Madobe
SQLite
JSONのパース
{ "users" : [ { "name" : "Claudia Madobe", "gender" : 0, "megane" : true }, { "name" : "Claude Madobe", "gender" : 1, "megane" : true } ] }
JSONObject
List<User> userList = new ArrayList<>();try { JSONObject jsonObject = new JSONObject(JSON); JSONArray users = jsonObject.getJSONArray("users"); for (int i = 0; i < users.length(); i++) { JSONObject userJson = users.getJSONObject(i); User user = new User(); user.setName(userJson.getString("name")); user.setGender(userJson.getInt("gender")); user.setMegane(userJson.getBoolean("megane")); userList.add(user); } Log.d(TAG, "count = " + userList.size()); for (User userData : userList) { Log.d(TAG, "name = " + userData.getName()); }} catch (JSONException e) {}
JSONObject
実行結果 count = 1 name = Claudia Madobe
name = Claude Madobe
JSONObject
{ "users" : [ { "name" : "Claudia Madobe", "gender" : 0, "megane" : true }, { "name" : "Claude Madobe", "gender" : 1, "megane" : true } ] }
@JsonModelpublic class User { public static final int GENDER_FEMALE = 0; public static final int GENDER_MALE = 1; @JsonKey private long id; @JsonKey private String name; @JsonKey private int gender = GENDER_FEMALE; @JsonKey private boolean megane = true;
JsonPullParser
https://github.com/vvakame/JsonPullParser
@JsonModelpublic class UserList { @JsonKey private List<User> users; public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; }}
JsonPullParser
https://github.com/vvakame/JsonPullParser
try { UserList userList = UserListGen.get(JSON); Log.d(TAG, "count = " + userList.getUsers().size()); for (User userData : userList.getUsers()) { Log.d(TAG, "name = " + userData.getName()); }} catch (IOException e) {} catch (JsonFormatException e) {}
JsonPullParser
https://github.com/vvakame/JsonPullParser
実行結果 count = 1 name = Claudia Madobe
name = Claude Madobe
JsonPullParser
https://github.com/vvakame/JsonPullParser
{ "users" : [ { "name" : "Claudia Madobe", "gender" : 0, "megane" : true }, { "name" : "Claude Madobe", "gender" : 1, "megane" : true } ] }
Deprecated(非推奨)
Deprecated
118
Apache HTTP Client API Level 22でdeprecatedに指定。
compileSdkVersion 23で、通常ではビルドできない扱いに。
•URLConnection
•OkHttp
Deprecated
119
Camera API API Level 21でdeprecatedに指定。
Nexus 5XなどではCamera APIをそのまま使うと、
カメラ映像が上下反転する不具合(仕様)有り
https://www.reddit.com/r/Android/comments/3rjbo8/nexus5x_marshmallow_camera_problem/cwqzqgh
•Camera2 API
まとめ
120
• オープンソースライブラリーの活用は、開発効率や性能の向上に繋がる。
新しいOSSの登場やバージョンアップを注視する必要がある。
• 非推奨(deprecated)に指定されて使えなくなったり、使用すると不具
合が発生するAPIも出はじめた。