2013年8月30日金曜日

エラー:Androidでのundefined reference to 'foo()'への対処

AndroidのNDKを使った開発で、undefined reference to 'foo()'が出た場合の対処例のメモ。

1.android.mkのLOCAL_SRC_FILESにfooを宣言しているファイル(例えばfoo.c)があることを確認

LOCAL_SRC_FILES := foo.c


2.(fooがcppファイルで宣言されていて、cファイルからの参照するときにエラーが出る場合のみ) foo()を宣言しているヘッダがextern "C"{}で囲われていることを確認(includeガードをしている場合は最初のincludeでこうなっていることを確認)

extern "C" {
#include "foo.h"
}

3.(別のライブラリとしてビルドしている場合のみ)android.mkのライブラリー関連の記述が正しいか確認

以下のようにfoo.cを含むライブラリーを静的ライブラリとしている場合は、
LOCAL_MODULE := bar
LOCAL_SRC_FILES := foo.c
include $(BUILD_STATIC_LIBRARY)

呼び出し側のライブラリの記述に以下を追加
LOCAL_STATIC_LIBRARIES := bar

共有ライブラリとしている場合( include $(BUILD_SHARED_LIBRARY) )は
LOCAL_SHARED_LIBRARIES := bar



2013年6月30日日曜日

ActivityUnitTestCaseでjava.lang.RuntimeException:

以下のようなコードを書いた
public class SampleTest extends ActivityUnitTestCase<MainActivity> {

 public SampleTest (
   Class<MainActivity> activityClass) {
  super(activityClass);
 }
}
このコードだと以下のようなエラーを吐いて、テストが始まる前に落ちる。
このコンストラクタは、1行目だけ書いた段階でEclipseのQuick Fixで生成されたコンストラクタ。でもこれだと動かない。
java.lang.RuntimeException: Exception during suite construction at android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests.testSuiteConstructionFailed(TestSuiteBuilder.java:239)

解決策はパラメータの無いコンストラクタを用意すること。


public class SampleTest extends ActivityUnitTestCase<MainActivity> {
 public SampleTest ( ) {
  super(MainActivity.class);
 }

}

これで動く。

2013年6月28日金曜日

ViewPagerのスライド速度変更

ViewPagerをフリックした時の画面の切り替わりが遅いと、縦方向のスクロールビュー(リストビュー等)と組み合わせると相性が悪い。
フリックした直後に縦にスクロールしようとしても、スワイプ動作がViewPagerの方に取られてしまうからだ。

スライドのアニメーションの速度を上げればこの問題は解決する。
やり方は下記に書いてあった。
http://stackoverflow.com/questions/8155257/slowing-speed-of-viewpager-controller-in-android

ポイントは
1.自前のScrollerを定義して、startScrollをOverrideし速度を好きな値にする
2.ViewPagerのmScrollerに1で定義したScrollerを使う。
※ただしViewPager::mScrollerはprivateなのでリフレクションを使う必要がある。

ソースコードは上記ページを参照のこと。

2013年4月17日水曜日

objective-cのswitch文でexpected expressionエラー

objective-cのswitch文でcase文の直後に変数宣言をするとexpected expressionというエラーが発生する。
switch( hoge ){
    case 0:
       int i; // expected expression
       break;
}

解決方法は簡単で、case文内でスコープを定義すれば良い。
switch( hoge ){
    case 0:
       {
           int i;
           break;
      }
}

理由はObjective-C勉強室というサイトに載っていた。以下引用。
 古いCの場合、ローカルに新規の変数を使う場合は必ず新しいスコープの先頭(宣言文以外が出てくるまで)に宣言しなければならなかったが、 Objective-Cではこれがかなり緩くなる。本当は最近のCの規格ではそういうものらしい。 ただし、一部例外がある。
(中略)switch文のcase文の直後に宣言するときのみ、新規スコープの宣言が必要

だそうです。

2013年2月28日木曜日

YOUR PHONE MAY NOT BE PROVISIONED FOR DATA SERVICES

アカウントのセットアップ時にYOUR PHONE MAY NOT BE PROVISIONED FOR DATA SERVICESというエラーが出た。

原因は日付・時刻が正しく無かったためであった。
( しばらく起動してなかったので時刻は1970/1/1 09:00に・・・ )

これを現在時刻に直してから試したら成功した。


2013年1月29日火曜日

(iOS) UISlider::setValueでsliderが再描画されない。

UISlider::setValueはUIスレッドから呼び出さないと再描画処理が行われません。
別スレッドから読んでいる場合はUIスレッドから呼ぶようにしましょう。

[self performSelectorOnMainThread:@selector(updateSlider) withObject:nil waitUntilDone:NO];

ExtAudioFileSeek→ExtAudioFileReadでError -50

iOSで音楽の読み込みを行うAPIにExtAudioFileRead( fileReference , size,  buffer )がある。

また、シークするAPIとしてExtAudioFileSeek( fileReference, seekTo )がある。

ExtAudioFileSeekを呼び出すことで読み出し位置を変更できるのだが、ファイルを最後まで読みだした後にExtAudioFileSeekで適当な位置にシークし、再びExtAudioFileReadで読みだしても、error -50が返され読み出しに失敗する。(読み出しバイト数は0となっている。)

全然原因がわからなくて調べていたら全く同じ内容で困ってる人がいた

なんと、バッファのサイズを示すbuffer->mBuffers[i].mDataByteSizeが、ExtAudioFileReadで読み出されたデータのバイト数で上書きされてしまうとのこと。

なので、ファイル終端まで再生すると、ファイル終端では読み出されるデータのバイト数が0になるため、buffer->mBuffers[i].mDataByteSizeも0になってしまう。

で、その後シークして読み出そうとしても、サイズ0のバッファをExtAudioFileReadに渡した事になり、データの読みだしが1byteも行われないのである。

というわけで、解決策はExtAudioFileReadを実行したら必ずbuffer->mBuffers[i].mDataByteSizeを実際に確保しているバッファサイズで上書きすること。

ExtAudioFileRead(fileReference, &size, buffer);
for(UInt32 i=0 ; isourceBuffer->mNumberBuffers ; i++){
   buffer->mBuffers[i].mDataByteSize = BUFF_SIZE;
}

ExtAudioFileReadの2つ目の引数sizeが、読みだすサイズの指定をしながら、実際に読み出されたbyte数で上書きされる、っていう仕様はまぁよくある話だけど、さらに他の引数で与えた構造体のメンバも同じデータで上書きするってのはちょっと仕様としてどうなの?これはExtAudioFileReadのリファレンスに何か書いてくれなきゃわかんないよう。