カテゴリー : 2013年 6月

[Mac] Finder の環境設定メモ [2013年版]

Mac の Finder の環境設定をメモ。

finde_config1

finder-config2

finder-config3

以上です。

[MacOS] システム環境設定の設定メモ [2013年版]

Mac の「システム環境設定」の個人用設定メモをご紹介します。

system-config

続きを読む

[Android] Google Analytics の使い方の参考情報

Android アプリで、Google Analytics を使うために参考にした情報をまとめました。

Google Analytics 公式ドキュメント

Google Analytics SDK for Android v2 (Beta) – Overview

Google Play のダウンロードがどこ経由かトラッキングするためのキャンペーンのパラメータ付きURLを簡単に生成できるツール
Campaign Measurement – Android SDK – Google Analytics

チームEGGによる翻訳ドキュメント

① 「概要」
②「高度な設定」
③「キャンペーントラッキング」
④「クラッシュと例外」
⑤「ディスパッチング」
⑥「eコマーストラッキング」
⑦「イベント」
⑧「スクリーン」
⑨「セッション」
⑩「ユーザータイミング」
⑪「EasyTrackerパラメータ」

[Android] Facebook SDK でエラー : Failure delivering result ResultInfo{who=null, request=64206, result=0, data=null} to activity {com.example/com.facebook.LoginActivity}: java.lang.NullPointerException

Facebook SDK for Android v3.0 でログイン処理時に NullPointerException エラーが発生しました。

Stack Trace
0	java.lang.RuntimeException: 
Failure delivering result ResultInfo{who=null, request=64206, result=0, data=null}
to activity {com.example/com.facebook.LoginActivity}: java.lang.NullPointerException
1		at android.app.ActivityThread.deliverResults(ActivityThread.java:2980)
2		at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023)
3		at android.app.ActivityThread.access$1100(ActivityThread.java:123)
4		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177)
5		at android.os.Handler.dispatchMessage(Handler.java:99)
6		at android.os.Looper.loop(Looper.java:137)
7		at android.app.ActivityThread.main(ActivityThread.java:4424)
8		at java.lang.reflect.Method.invokeNative(Native Method)
9		at java.lang.reflect.Method.invoke(Method.java:511)
10		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
12		at dalvik.system.NativeStart.main(Native Method)
13	Caused by: java.lang.NullPointerException
14		at com.facebook.AuthorizationClient$KatanaProxyAuthHandler.onActivityResult(SourceFile:645)
15		at com.facebook.AuthorizationClient.onActivityResult(SourceFile:142)
16		at com.facebook.LoginActivity.onActivityResult(SourceFile:134)
17		at android.app.Activity.dispatchActivityResult(Activity.java:4676)
18		at android.app.ActivityThread.deliverResults(ActivityThread.java:2976)
19		... 11 more
20	java.lang.NullPointerException
21		at com.facebook.AuthorizationClient$KatanaProxyAuthHandler.onActivityResult(SourceFile:645)
22		at com.facebook.AuthorizationClient.onActivityResult(SourceFile:142)
23		at com.facebook.LoginActivity.onActivityResult(SourceFile:134)
24		at android.app.Activity.dispatchActivityResult(Activity.java:4676)
25		at android.app.ActivityThread.deliverResults(ActivityThread.java:2976)
26		at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023)
27		at android.app.ActivityThread.access$1100(ActivityThread.java:123)
28		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177)
29		at android.os.Handler.dispatchMessage(Handler.java:99)
30		at android.os.Looper.loop(Looper.java:137)
31		at android.app.ActivityThread.main(ActivityThread.java:4424)
32		at java.lang.reflect.Method.invokeNative(Native Method)
33		at java.lang.reflect.Method.invoke(Method.java:511)
34		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
35		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
36		at dalvik.system.NativeStart.main(Native Method)

Facebook SDK for Android v3.0 のバグらしいので、v3.0.1 にアップデートすることで解決します。

参考情報

[Node.js] コマンドライン引数をカンタンに扱えるモジュール「commander.js」

Node.js で、コマンドライン引数をカンタンに扱えるモジュール「commander.js」がとても便利です!

visionmedia/commander.js · GitHub

[Node.js] http.request で [Error: socket hang up] code: ‘ECONNRESET’

Node.js で HTTPS リクエストを生成するコードで [Error: socket hang up] code: ‘ECONNRESET’ というエラーが発生しました。

エラーメッセージ

Error: socket hang up
    at createHangUpError (http.js:1124:15)
    at Socket.socketOnEnd [as onend] (http.js:1272:23)
    at TCP.onread (net.js:389:26)

HTTPS リクエストを送るのに、https モジュールじゃなく http モジュールを使っていたのが原因でした…

なので、下記のようにちゃんと https モジュールを使えばOKです。

var https = require('https');
 
/**
 * HTTPS POST (JSON)
 *
 * @param {Object} jsonData
 * @param {Function} callback
 * @param {String} encoding
 */
function httpJsonPost(jsonData, callback, encoding) {
  jsonData = jsonData || {};
  encoding = encoding || 'utf8';
 
  var jsonDataString = JSON.stringify(jsonData);
 
  var headers = {
    'Content-Type': 'application/json',
    'Content-Length': jsonDataString.length
  };
 
  var options = {
    host: 'api.example.com',
    port: 443,
    path: '/1/push',
    method: 'POST',
    headers : headers
  };
 
  var req = https.request(options, function(res) {
    res.setEncoding(encoding);
 
    var responseString = '';
 
    res.on('data', function(chunk) {
      responseString += chunk;
    });
 
    res.on('end', function() {
      var resultObject = JSON.parse(responseString);
      return callback(null, resultObject, res.statusCode, JSON.stringify(res.headers));
    });
  });
 
  req.on('error', function(e) {
    return callback(e);
  });
 
  req.write(jsonDataString);
  req.end();
}

[参考情報]

HTTPS Node.js v0.11.2 Manual & Documentation

[Parse.com] REST API で Push Notification を送信する方法

Parse.com の REST API でプッシュ通知配信する curl コマンドを用途別にご紹介します。

[参考]: Push Developer Guide | Parse


全てのアプリにプッシュ通知配信

curl -X POST \
  -H "X-Parse-Application-Id: xxxxxxxxxx" \
  -H "X-Parse-REST-API-Key: xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "data": {
          "alert": "This is a notification message!"
        }
      }' \
  https://api.parse.com/1/push

Android アプリにプッシュ通知配信

curl -X POST \
  -H "X-Parse-Application-Id: xxxxxxxxxx" \
  -H "X-Parse-REST-API-Key: xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "android",
        },
        "data": {
          "alert": "This is a notification message!"
        }
      }' \
  https://api.parse.com/1/push

iOS アプリにプッシュ通知配信 [2013年6月26日23時00分(現地時間)]

curl -X POST \
  -H "X-Parse-Application-Id: xxxxxxxxxx" \
  -H "X-Parse-REST-API-Key: xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "ios",
        },
        "push_time": "2013-06-26T23:30:00",
        "data": {
          "alert": "This is a notification message!"
        }
      }' \
  https://api.parse.com/1/push

iOS アプリにプッシュ通知配信 [2013年6月26日23時00分(現地時間)]
かつ、アプリ側で notificationTime を 23:30 を設定するもののみに、プッシュ通知配信

curl -X POST \
  -H "X-Parse-Application-Id: xxxxxxxxxx" \
  -H "X-Parse-REST-API-Key: xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "where": {
          "deviceType": "ios",
          "notificationTime": "23:30"
        },
        "push_time": "2013-06-26T23:30:00",
        "data": {
          "alert": "This is a notification message!"
        }
      }' \
  https://api.parse.com/1/push

[Android] IllegalStateException: Cannot add header view to list : setAdapter has already been called.

Android アプリ開発にて、ListFragment で setListAdapter した後に addHeaderView や addFooterView を呼び出すと java.lang.IllegalStateException 例外が発生して、アプリがクラッシュしてしまいます。

Android 4 系だと例外は発生しなくて、Android 2.3 系だと例外でクラッシュするみたいです。

Stack Trace
_________________________________
0	java.lang.RuntimeException: Unable to resume activity {com.example/com.example.activity.MainActivity}:
 java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
1		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2124)
2		at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139)
3		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
4		at android.os.Handler.dispatchMessage(Handler.java:99)
5		at android.os.Looper.loop(Looper.java:123)
6		at android.app.ActivityThread.main(ActivityThread.java:3691)
7		at java.lang.reflect.Method.invokeNative(Native Method)
8		at java.lang.reflect.Method.invoke(Method.java:507)
9		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
10		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
11		at dalvik.system.NativeStart.main(Native Method)
12	Caused by: java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
13		at android.widget.ListView.addHeaderView(ListView.java:336)
14		at android.widget.ListView.addHeaderView(ListView.java:359)
15		at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358)
16		at com.example.fragment.NewFragment.onResume(NewFragment.java:143)
17		at android.support.v4.app.Fragment.performResume(Fragment.java:1503)
18		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
19		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
20		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
21		at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871)
22		at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455)
23		at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444)
24		at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69)
25		at android.app.Activity.performResume(Activity.java:3867)
26		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114)
27		... 10 more
28	java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
29		at android.widget.ListView.addHeaderView(ListView.java:336)
30		at android.widget.ListView.addHeaderView(ListView.java:359)
31		at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358)
32		at com.example.fragment.NewFragment.onResume(NewFragment.java:143)
33		at android.support.v4.app.Fragment.performResume(Fragment.java:1503)
34		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
35		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
36		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
37		at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871)
38		at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455)
39		at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444)
40		at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69)
41		at android.app.Activity.performResume(Activity.java:3867)
42		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114)
43		at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139)
44		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
45		at android.os.Handler.dispatchMessage(Handler.java:99)
46		at android.os.Looper.loop(Looper.java:123)
47		at android.app.ActivityThread.main(ActivityThread.java:3691)
48		at java.lang.reflect.Method.invokeNative(Native Method)
49		at java.lang.reflect.Method.invoke(Method.java:507)
50		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
51		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
52		at dalvik.system.NativeStart.main(Native Method)

正しいコード

// addHeaderView 後に setListAdapter
listView.addHeaderView(headerView);
listView.addFooterView(footerView);
 
setListAdapter(arrayAdapter);

IllegalStateException でクラッシュするコード

// setListAdapter 後に addHeaderView
setListAdapter(arrayAdapter);
 
listView.addHeaderView(headerView);
listView.addFooterView(footerView);

必ず setListAdapter する前に、addHeaderView や addFooterView を呼び出すようにしましょう。

[参考]

Note to self: ListFragment and header views

android – ListFragment add headerView gives java.lang.IllegalStateException:alled – Stack Overflow

Android – ListActivity, add Header and Footer view – Stack Overflow

android – How to add footer view dynamically – Stack Overflow

[Android] RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

開発中の Android アプリが、下記のエラーでクラッシュしました。

RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

原因は、doInBackground() 内で UI に関する処理を行なっていたためでした。
(具体的には、エラーメッセージを Toast で表示しようとしていた)

エラーが発生したときは、doInBackground() 内でエラーダイアログの表示などは行わず return null を返して、 onPostExecute メソッド内で良しなにエラー通知をするべきです。

メソッドdoInBackgroundはUIスレッドとは別なプールから取得されたスレッド上で実行されるのでGUI操作をしてはならない。代わりにUTスレッドと同期されるonProgressUpdateやonPostExecuteメソッド内でGUI操作を完了できる。

[引用]:バックグラウンドスレッドでダイアログを生成してはいけない – Kazzzの日記

[参考]

Android Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow

android – Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow

[Android] リアルタイムでクラッシュレポートを自動送信するサービスまとめ

Android アプリに、リアルタイムでクラッシュレポートを自動送信するサービスやツールをまとめてみました。

Crittercism

Crittercism | Mobile Application Performance Management

スマートフォンアプリのクラッシュログ解析サービス (crittercism と bugsense) を使ってみた – むらかみの雑記帳

BugSense

BugSense | Crash Reports and Operational Intelligence for Android, iOS, Windows Phone & Windows 8 apps

超簡単!BugSenseでスマホアプリ/サイトのクラッシュ統計をとろう | Developers.IO

ACRA (Application Crash Report for Android)

ACRA/acra · GitHub

Android ACRAを使ってアプリのクラッシュ情報を自動送信する方法 | Tech Booster

以上です。