DroidKaigi 2017で登壇してきた

2日目の16:00から「Error Handling in RxJava」というタイトルで、RxJavaにおけるエラーハンドリングについて発表してきました。

スライド

概要

  • RxJavaのおさらい

    • Reactive Extensions for Java
    • マーブルダイアグラム
  • RxJavaにおけるエラーハンドリング

    • Catch(エラー発生時にリカバリーを行う)
      • onError: エラーをキャッチする
      • onErrorReturn: エラーをキャッチして代わりのデータを返す
      • onErrorResumeNext: エラーをキャッチして代わりのObservableを返す
    • Retry(エラー発生時にresubscibeを行う)
      • retry: エラーをキャッシュしてresubscribeする
      • retryWhen: resubscribeする条件を細かく制御する
  • 基礎編

    • エラーをトーストで表示する:onError
    • 代わりのデータを表示する:onErrorReturn
    • エラーの種類で処理を分岐する:onErrorResumeNext
    • リトライする:retry
    • リトライするかをユーザーに尋ねる:retryWhen
  • 応用編

    • リトライ&キャッシュ:retry, onErrorReturn
    • リトライ&キャッシュ&トースト:retry, onErrorReturn, onError
  • 実践編

    • Retrofitのエラーハンドリング
      • RxJavaCallAdapterの拡張

振り返り・感想

資料

1日目の終了後に自分の資料を改めて見直して、後から資料単体で見た場合に情報量が少なく分かりにくいのでは、ということに気が付き資料を修正した。修正後に一度だけ通しで練習をしたものの、基本的には情報量を増やす方向で修正を行ったので、当日は少し急ぎで喋った。結果として、中盤を過ぎた辺りで早すぎることに気が付き、後半は少しゆっくりと喋った。

直前に資料修正は良くないし、発表練習では話す内容だけでなく、タイムマネジメントも含めて練習すべきという当然の学びを得た。

登壇直前

ありがたいことに自分のセッションは立ち見が出た。

セッション前の静かな会場の雰囲気に耐えられず、登壇者席からiPhoneでパノラマで写真を撮るということをやってみた。

登壇中

前回のDroidKaigiでも同じような規模の部屋で登壇していたこともあり、今回は過度に緊張せずに喋れたと思う。発表中に聞いている人の表情や頷き具合とかを観察しながら説明の仕方を調整する余裕もあった。具体的には「RxJavaにおけるエラーハンドリング」のところでretryまでは頷きながら聞いてくれる人がかなりいたので練習のときよりも説明を軽めにして、retryWhenに入った辺りから今まで頷いてくれていた人の表情が曇り始めたのでより詳細に説明するようにした。

登壇後

登壇後はオフィスアワーとして質問を受けていましたが、その場で分かりやすかったです!と言っていただけたり、Twitterでもいくつか反響をいただけたりして素直に嬉しかった。

retryWhenは説明不足なところもあった模様。反省。

まとめ

プロポーザルを出す前はこんなネタで登壇していいのか悩んだが、結果的には登壇して本当に良かったと思います。同僚のlvla0805がオープニングトークでも言っていましたが、自分の当たり前は必ず誰かに需要があるので、悩んだらとりあえずプロポーザルを出せばいいんじゃないかなと思います。僕は来年も絶対プロポーザルを出します。

起動時に読み込まれるActivityを変更する際の注意点

AndroidアプリはAndroidManifest.xmlで起動Activityを設定しますが、既にリリース済みのアプリの起動Activityを変更すると、アップデートしたユーザーがアプリを起動できなくなる場合があります。若干ハマったので原因と対策をメモっておきます。

環境

再現方法

サードパーティ製のホームアプリ等を利用して、ホーム画面にショートカットを配置します。その状態で起動Activityの名前を変更して、上書きインストールします。そして、ホーム画面にあるショートカットをタップすると、「アプリケーションが見つかりません」というエラーが表示されて、アプリを実行することが出来なくなります。

再現確認の取れたホームアプリは以下の2つです。 といっても、これ以外にはNova Launcher 3.3しか試してないですが。。

  • Zeam Launcher 3.1.10
  • ADW.Launcher 1.3.3.9

原因

Activity名を直接指定するタイプ?のショートカットを作るホームアプリを使用してショートカットを作成している場合に、起動Activityの名前を変更してしまうとショートカットが無効になってしまう。

対策

起動Activityに変更を加える場合に、名前は変更しないようにしましょう。

Androidアプリを高速化しよう -ANR編-

はじめに

この投稿はAndroid Advent Calendar 30日目の記事です。

前回の25日目では目に見えないボトルネックを探す手法を紹介しましたが、今回はAndroidアプリケーション開発を行う上で避けては通れないANRとその対処法について書きます。

環境

この記事で紹介するソースコードの動作確認は以下の環境で行いました。

また、この記事で紹介するコードは以下のリポジトリにあります https://github.com/yuyakaido/AndroidAdventCalendar2014

ANR (Application Not Responding)

ANRとはメインスレッド上で重たい処理を行った際に表示される警告で、ユーザーには「〜は応答していません」というダイアログとして表示されます。ここで言う重たい処理というのは具体的には以下の通りです。

  • メインスレッド上で5秒以上かかる処理を実行した
  • BroadcastReceiverが10秒以内で終了しない

実験

では、実際にANRを発生させてみます。

アプリに適当なボタンを配置してそれを押すと以下のコードが実行されるようにします。

try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

アプリケーションを実行し、ボタンを押してしばらくすると以下のようにANRが発生します。

f:id:yuyakaido:20141230154001p:plain

対処法

上記のサンプルでは原因が明らかですが、実際はコードがもっと複雑で一見するとどこが原因となっているのかを特定するのが困難である場合がほとんどだと思います。ですが、実はANRは端末内の以下のファイルに逐一記録されています。

/data/anr/traces.txt

上記のファイルを確認することでANRの原因を特定することが可能となります。

adbを用いて端末内のtraces.txtをローカルマシンに持ってきます。

adb pull /data/anr/traces.txt ~/

ANRのログはこのファイルの先頭に逐一追加されていきます。 ローカルマシンに持ってきたファイルを開いてみると、以下のように先程の実験で発生させたANRが記録されていました。

----- pid 1219 at 2014-12-30 06:54:15 -----
Cmd line: com.yuyakaido.androidadventcalendar2014

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0xa62904b0 self=0xb9109510
  | sysTid=1219 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1216953280
  | schedstat=( 81308922 43683273 389 ) utm=6 stm=1 core=0
  at java.lang.VMThread.sleep(Native Method)
  at java.lang.Thread.sleep(Thread.java:1031)
  at java.lang.Thread.sleep(Thread.java:1013)
  at com.yuyakaido.androidadventcalendar2014.MainActivity.performApplicationNotRespondingTest(MainActivity.java:71)
  at com.yuyakaido.androidadventcalendar2014.MainActivity.access$400(MainActivity.java:17)
  at com.yuyakaido.androidadventcalendar2014.MainActivity$5.onClick(MainActivity.java:63)
  at android.view.View.performClick(View.java:4084)
  at android.view.View$PerformClick.run(View.java:16966)
  at android.os.Handler.handleCallback(Handler.java:615)
  at android.os.Handler.dispatchMessage(Handler.java:92)
  at android.os.Looper.loop(Looper.java:137)
  at android.app.ActivityThread.main(ActivityThread.java:4745)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:511)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
  at dalvik.system.NativeStart.main(Native Method)

このようにtraces.txtを参照することでANRの原因を特定することが出来ました。原因が分かってしまえば後は煮るなり焼くなりしてしまいましょう。

さいごに

この年末はAndroidではなく、ひたすらSwiftiOSアプリを開発しています。決してAndroid開発に嫌気がさしたわけではないですよ?

それではAndroid開発者の皆様、良いお年を!

Androidアプリを高速化しよう

はじめに

この投稿はAndroid Advent Calendar 2014の25日目の記事です。

Androidアプリの開発をしていたのがきっかけで彼女が出来たyuyakaidoです。昨日のkaneshinthさんの記事の冒頭にあるように僕はマルチスレッド初心者なので常にシングルスレッドで動作しています。勿論クリスマスイブも。

今回は既存のアプリケーションのボトルネックを探すための手法を紹介していこうと思います。

お品書き

  • StrictMode
    • パフォーマンスに影響を及ぼすコードの検出
  • Traceview
    • パフォーマンス計測ツール
  • その他
    • Viewのネストについて
    • Viewの塗り潰しについて

環境

この記事で紹介するソースコードの動作確認は以下の環境で行いました。

StrictMode

StrictModeはGingerbreadから追加された機能で、アプリケーションのパフォーマンスに影響を及ぼす可能性のあるコードを検出してくれるものです。StrictModeはポリシーという形で何を検出するかを自由に設定することが出来ます。

使用方法

実際にコードを交えつつStrictModeの使用方法を解説していきます。

まず、StrictModeを有効にするためにカスタムApplicationクラスのonCreate()、もしくはアプリケーションのエントリーポイントとなるActivityのonCreate()に以下のコードを追加します。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()
                .penaltyLog()
                .build());

上記で設定したポリシーに違反するコードが検出された場合はlogcatにその旨が出力されます。新規で作成したプロジェクトに上記のコードを追加して実行した場合には何も出力されないのが確認出来るかと思います。

では、上記で設定したポリシーに違反するコードを書いてみましょう。適当な新規プロジェクトを作成して以下のコードを任意の箇所に記述してください。

String fileName = "sample.txt";
String fileContent = "Hello Android Advent Calendar!!";

File file = new File(Environment.getExternalStorageDirectory(), fileName);

try {
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    fileOutputStream.write(fileContent.getBytes());
    fileOutputStream.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

上記のポリシーに違反しているコードを追加してアプリを実行してください。するとlogcatに以下のようなログが表示されるはずです。

12-20 21:08:33.894    5064-5064/com.yuyakaido.androidadventcalendar2014 D/StrictMode﹕ StrictMode policy violation; ~duration=24 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2
            at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1089)
            (省略)
12-20 21:08:33.894    5064-5064/com.yuyakaido.androidadventcalendar2014 D/StrictMode﹕ StrictMode policy violation; ~duration=8 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=31 violation=1
            at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1063)
            (省略)

上記のログからディスク読み込み・書き込みに関するポリシー違反が検出されたことが分かります。 上記の2つのポリシー違反は以下の2行で発生しています。

  • 読み込み: FileOutputStream fileOutputStream = new FileOutputStream(file);
  • 書き込み: fileOutputStream.write(fileContent.getBytes());

上記はかなり単純な例でしたが、もう少し実践的な例を見てみましょう。 ActiveAndroidでデータをDBに保存して、その保存したデータをDBから取り出す場合を考えてみます。 ActiveAndroidに関しては、20日目のandrohiさんの記事をご参照ください。

まず、保存対象となるモデルクラスを用意します。

@Table(name = "Items")
public class Item extends Model {

    @Column(name = "Name")
    public String name;

}

次に先ほど作成した新規プロジェクトの任意の箇所に以下のコードを記述します。

Item item = new Item();
item.name = "NAME";
item.save();
item = new Select().from(Item.class).executeSingle();

上記のコードを追加してアプリケーションを実行すると、logcatに以下のようなログが出力されるはずです。

12-20 21:18:56.758    5350-5350/com.yuyakaido.androidadventcalendar2014 D/StrictMode﹕ StrictMode policy violation; ~duration=32 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=31 violation=1
            at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1063)
            at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:226)
            at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:84)
            at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2020)
            at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1960)
            at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:736)
            at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:273)
            at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:115)
            at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1839)
            at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1712)
            at com.activeandroid.Model.save(Model.java:155)
            at com.yuyakaido.androidadventcalendar2014.MainActivity.ActiveAndroidTest(MainActivity.java:27)
            at com.yuyakaido.androidadventcalendar2014.MainActivity.onCreate(MainActivity.java:21)
            at android.app.Activity.performCreate(Activity.java:4470)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
            at android.app.ActivityThread.access$600(ActivityThread.java:128)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4514)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
            at dalvik.system.NativeStart.main(Native Method)
12-20 21:18:56.758    5350-5350/com.yuyakaido.androidadventcalendar2014 D/StrictMode﹕ StrictMode policy violation; ~duration=10 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2
            at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1089)
            at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1678)
            at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1659)
            at com.activeandroid.util.SQLiteUtils.rawQuery(SQLiteUtils.java:106)
            at com.activeandroid.util.SQLiteUtils.rawQuerySingle(SQLiteUtils.java:122)
            at com.activeandroid.query.From.executeSingle(From.java:311)
            at com.yuyakaido.androidadventcalendar2014.MainActivity.ActiveAndroidTest(MainActivity.java:28)
            at com.yuyakaido.androidadventcalendar2014.MainActivity.onCreate(MainActivity.java:21)
            at android.app.Activity.performCreate(Activity.java:4470)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995)
            at android.app.ActivityThread.access$600(ActivityThread.java:128)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4514)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
            at dalvik.system.NativeStart.main(Native Method)

上記のログ内のスタックトレースを見るとDBに書き込む時、DBから読み込む時にポリシー違反が発生していることが分かると思います。

Traceview

TraceviewはAndroid SDKに付属しているパフォーマンス計測のためのツールで、開発中のアプリケーション内で実行されるメソッドの実行時間の計測や時系列の表示、メソッドのコールスタックの可視化等高速化の役に立つであろう様々な計測を行うことが出来ます。 以前はソースコードに計測開始・計測終了を指定するメソッドを埋め込まなければならず、さらに計測結果のファイルが端末内に保存されるためadb pullでホストマシンに引っ張ってくる必要がある等かなり面倒でしたが、Android Studio 1.0.1ではIDE上で計測開始・計測終了時にボタンを押すだけで良くなり、簡単にパフォーマンス計測を行うことが可能になりました。

使用方法

今回は簡単のために画面上に配置されたボタンを押すと以下の処理が走るようにします。

try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

以下のように画面上に適当なボタンを配置してそのボタンを押すと上記のコードが実行されるようにします。

f:id:yuyakaido:20141221001514p:plain

そして、Android Studio上で以下の画像で示す操作を行うことで簡単にパフォーマンス計測を行うことが出来ます。

f:id:yuyakaido:20141221001350p:plain

  • ①: Android DDMSを開く
  • ②: パフォーマンス計測を行うプロセスを選択(今回はcom.yuyakaido.androidadventcalendar2014を選択)
  • ③: 計測開始
  • ④: 計測終了

上記の操作を行うと以下に計測結果が表示されるはずです。

f:id:yuyakaido:20141221003359p:plain

上半分にはUIスレッド上の処理が時系列順に並んでいます。下半分には全メソッドの実行時間や総実行時間に対する各メソッドの実行時間の割合等が表示されています。

次にTraceviewの実践的な使い方を見ていきましょう。 Traceviewはメソッドのコールスタックを追うことが出来ます。

画面にボタンを追加して、そのボタンを押すと以下の処理が走るようにします。

ActiveAndroid.beginTransaction();
try {
    for (int i = 0; i < 100; i++) {
        Item item = new Item();
        item.name = "NAME";
        item.save();
    }
    ActiveAndroid.setTransactionSuccessful();
} finally {
    ActiveAndroid.endTransaction();
}

上記のコードを追加した上でパフォーマンス計測を行った結果を以下に示します。

f:id:yuyakaido:20141221011747p:plain

処理が開始された時点を矢印で示しています。矢印の少し下を見ると上記の処理が書かれているMainActivity.performActiveAndroidTransaction()が実行されていることが分かるかと思います。そして、このメソッド内ではsaveメソッドが100回呼ばれているので、MainActivity.performActiveAndroidTransactionの下にはModel.save()が並んでいます。

このようにTraceviewを使えばメソッドのコールスタックを辿ることが出来ます。このコールスタックを下からみていき、自分のプロジェクトパッケージに行き当たればその部分が根本原因であると特定することが出来ます。

その他

  • Viewのネストについて

15日目でkonifarさんも触れていますが、Viewのネストはパフォーマンスを低下させる一因になります。一般にLinearLayoutよりもRelativeLayoutを使った方がViewのネストが浅くなります。とはいえ、既存のものを書き換えるのはコスパが悪いので、そこまで神経質に全てを書き換える必要はないと思います。新規で作るレイアウトに関してはネストの深さを意識してみると良いのではないでしょうか。

  • Viewの塗り潰しについて

こちらも同じ方がここで言及しているように無駄にViewの塗りつぶしをするのはパフォーマンスを低下させる一因になります。

おわりに

この記事で紹介したソースコードは以下のリポジトリにアップロードしています。

https://github.com/yuyakaido/AndroidAdventCalendar2014

x86・x64・IA-32・IA-64

x86IA-32って何が違うの?x64ってx86を64ビットに拡張したものだから、x64 = IA-64ということ?

OSをかじったりしていた割にこの辺が曖昧だったので調べてみた。といっても概要だけですが。

x86

一言で言えば、インテルが開発した8086とその後継CPUの命令セットアーキテクチャを指す言葉です。

インテルは1978年に8086、その後細かい派生を無視すると、80186、80286、8038680486という順番でCPUを開発しました。インテルが開発したCPUの名前は連番になっており、連番になっている部分をxで置き換えることで「x86」という名称が生まれました。

ちなみに、8086と80186と80286は16ビットCPU、8038680486は32ビットCPUです。そして、これらのCPUは良い意味でも悪い意味でも8086からの互換性を保っています。

IA-32IA-64

タイトルと順番が前後しますが、おそらくこちらを先に説明した方が分かりやすいため、IA-32IA-64を先に説明します。

インテルは1978年に8086を発売して以来、市場の強い要望により8086と互換性を持つCPUを発売してきたわけですが、そもそも8086は拡張性を意識したアーキテクチャではなく、インテルは苦し紛れの拡張を続けてきました。そこでインテルは8086から脈々と続いてきたx86の系譜を捨て、8086と互換性を持たない次世代の64ビット命令セットアーキテクチャとして「IA-64」を開発しました。IA-64を発表した際に今までの32ビット命令セットアーキテクチャ8038680486が採用している命令セットアーキテクチャ)に「IA-32」という名称を付けました。

インテルとしては当然IA-64を広めたいと考えていたようですが、市場はx86上で築き上げてきた莫大な資産を捨ててまでIA-64に移行したいとは思わなかったようで、現状としてIA-64はあまり普及していないようです。

x64

x64はその名前からも分かるように、x86を64ビット拡張したもので当然ながら8086との互換性を持ち合わせています。x86-64と書いてある場合もありますが、同じものを指します。

x64の開発の経緯を少し補足します。

x86は広く普及し、半導体技術とアーキテクチャの革新と共に性能向上を続けてきましたが、インテルIA-32の性能向上によって自社開発のIA-64との競合を懸念し、あえてx86の64ビット化を行いませんでした。しかし、市場としてはIA-32との互換性を保ちつつそれを64ビット化して欲しいわけです。そこでインテルではなくAMDx86を64ビット化し、AMD64として発表しました。その後にインテルAMD64を自社でもIntel 64として採用しました。AMD 64とIntel 64は微妙に異なる点はありますが、動作的にはほとんど同じものと考えてください。

まとめると、AMD 64とIntel 64等の各社が出している互換64ビット命令セットアーキテクチャを「x64」と言います。

一応確認ですが、x64とIA-64はまったく別物で互換性はありません。

2014年現在で一般用途PCのCPUにおいて一番採用されていると思われるCore iシリーズにはx86、x64の両命令セットが搭載されています。

余談

Ubuntuの64ビットイメージを落とすと、末尾にamd64と書いてある意味がやっと分かりました。

参考サイト

VMware Fusion上のWindows 7でUSB SuperDriveを使う方法

単純に繋げただけでは動作しません。私の環境ではディスクを吸い込んでくれませんでした。

作業環境

症状

VMware Fusion上でWindowsを立ち上げた状態でUSB SuperDriveを接続すると以下のようなポップアップが表示される。これは正常な動作です。

f:id:yuyakaido:20140222010524p:plain

ここで「Connect to Windows」を選択します。そうすると、Windowsが勝手にドライバのインストールを開始します。そのインストールが終わってもう使えるかと思いきや、ディスクを吸い込んでくれません。

原因

原因は調べるまでもなく上記のポップアップに書いてあります。

The device requires installation of the Apple Boot Camp driver in the virtual machine. Without this driver the device might not work properly or it might cause the guest operating system to fail.

このデバイスを動作させるためにはApple Boot Camp driverが必要です。さもなくば動作しないかゲストOSごと死ぬよ?

解決策

以下のMac製品を使っている方はここから

以下のMac製品を使っている方はここから

上記の2つから該当するリンク先を選択して、zipファイルをダウンロード・解凍してください。 解凍するとたくさんのドライバのインストーラが出てきますが、今回必要となるのは、BootCamp5.1.56XX/BootCamp/Drivers/Apple/AppleODDInstaller64.exeです。これを実行することでUSB SuperDriveを動作させるために必要となるドライバがインストールされ、無事動作するようになるはずです。

参考サイト

源泉徴収と還付申告

私が還付申告するにあたって調べたメモです。

源泉徴収

給与から所得税を差し引く制度のことを指します。源泉徴収の対象となる人が受け取るであろう年収を計算して、それに応じた額を差し引いた金額が実際に受け取る給与となります。ここでは他の税金等は無視して考えるものとします。

還付申告

日本では年間の給与所得が103万円以下の場合は所得税を取られることはありません。しかし、給与は基本的に源泉徴収制度によって所得税が差し引かれた上で受け取ることになります。従って当然所得税を返して貰う権利があるわけで、このための申告のことを還付申告と言います。給与所得が年間103万円以下の場合は源泉徴収票に書かれた源泉徴収額がそのまま戻ってきます。これはアルバイトでも当てはまります。

関連事項

  • 年末調整

源泉徴収は対象となる人の年収を仮定してそれに応じた額が毎月の給与から差し引かれます。この方式でいくと、年収が想定よりも少なかった場合は所得税を余分に取られてしまうことになります。当然逆もあり得ます。このような差額が発生した場合にそれを調整することを年末調整と言います。

  • 確定申告

私は関係ないですが、確定申告というものがあります。源泉徴収は基本的に給与所得がある人を対象としています。従って自営業など給与所得としての収入がない人はそのままでは所得税を払っていない事になります。当然それは脱税にあたるわけで、その年の収支を計算して申告しなければいけません。このことを確定申告と言います。