CursorTreeAdapterのsetChildrenCursorで落ちるのを回避してみる

(この対処が正しいのかはわかりません)

落ちるところ

ExpandableListView+CursorTreeAdapter+LoaderCallbacksで実装していて、

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.setChildrenCursor(ID, data);
    }

setChildrenCursorしようとするとNullPointerExceptionが出ることがある。

CursorTreeAdapter.javaの実装を見てみると、

    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
        
        /*
         * Don't request a cursor from the subclass, instead we will be setting
         * the cursor ourselves.
         */
        MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition, false);

        /*
         * Don't release any cursor since we know exactly what data is changing
         * (this cursor, which is still valid).
         */
        childrenCursorHelper.changeCursor(childrenCursor, false); // <- ここで落ちる
    }
    synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean requestCursor) {
        MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);
        
        if (cursorHelper == null) {
            if (mGroupCursorHelper.moveTo(groupPosition) == null) return null; // <- nullを返すことがある
            
            final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
            cursorHelper = new MyCursorHelper(cursor);
            mChildrenCursorHelpers.put(groupPosition, cursorHelper);
        }
        
        return cursorHelper;
    }

childrenCursorHelpernullになることがあり、changeCursor()を呼び出すのでNullPointerExceptionが出る。

・・nullチェックされていなくて涙目です。

が、nullになる状況を作り出している私のコードに問題があるのかもしれません。
(まだわかってない)

対処

以下のような応急処置をしました。

先にGroupCursorの生存を確認してから、setChildrenCursorするようにした。

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

        Cursor groupCursor = adapter.getGroup(ID);

        if (groupCursor == null) {
            return;
        }

        adapter.setChildrenCursor(ID, data);
    }

getGroupの中身は・・

    public Cursor getGroup(int groupPosition) {
        // Return the group Cursor pointing to the given group
        return mGroupCursorHelper.moveTo(groupPosition);
    }

先ほどの「nullチェックされてなくて涙目」な部分を、
「自分で事前にチェックしてみた」ということになった。

NullPointerExceptionをcatchしてやりすごすよりは、良いかな??

コントロールセンターとAVAudioEngine

AVAudioEnginestart/stop
コントロールセンターのplay/pauseと同期してる模様。

コントロールセンターでpauseしても「▶︎」に変わらなくてあれーと思っていたら
Engineをstopしたらちゃんと動作した。

AVAudioEngineは都度start/stopするのが正解なのかー。

MoreのtintColor

storyboardのGlobal Tintを設定しても、「More」と「Edit」にその色は反映されず。
TabBarControllerをカスタムしているせいなのかもしれないけど・・。

MoreNavigationControllerにはtintColorを設定できても、
More画面やEdit画面そのものには設定できないので
半ばやけくそ気味にAppDelegate.m

[self.window setTintColor:[UIColor ...]];

としたらMoreもEditも変わってた。ふーむ・・

iPod library アルバムのリリース年を取得

iPodライブラリからアルバム情報を取ってきて、リリース日(年)を表示したいのだが

MPMediaItemCollection *album;(←値の代入処理は省略)
MPMediaItem *item = [album representativeItem];
NSDate *date = [item valueForProperty:MPMediaItemPropertyReleaseDate];

dateはnilになってしまう。

NSNumber *num = [item valueForProperty:@"year"]

これならリリース年が取れる。

ちなみに、 @"month"@"day"を試してみたけど
どちらもnum = nilでした。
@"year"のみ有効な模様。

XCode6.1, iOS8.0での話でした。

AVAudioPlayerNodeのresume

自分の探索能力の低さを呪っているところ。よってメモ。

こちらのサンプル(AVAudioPlayerNodePlayPause)によって一つの解法を得ました
この方ありがとう><
でもこの方も困ってる様子…。
私はlastRenderTimeを使って再開するのかなと四苦八苦していたので、目から鱗の手法。

Nodeのplay/pauseの際に、Engineのstop/(re)startもする。

  • scheduleFileの場合は、Engineのstop/startでresumeできる。
  • scheduleBufferの場合は、↑してもresumeできない。

では、Bufferの場合はどうすればよいのかと…。

謎多きPlayerNodeとの戦いは続く(?)

AVAudioPlayerNodeのループ再生

地味にハマったのでメモ。

AVAudioPlayerNodeでループ再生

ポイントは、initWithPCMFormatprocessingFormatを指定すること。
fileFormatの方を指定していてinitでコケてた。
これだけなのに、しばらく困り果ててた。。