おすしたべたい

おすしがたくさん食べられるようにがんばるブログ

AndroidでURLエンコード

通信用ライブラリにはVolleyを利用していますが、クエリに日本語が含まれるとうまくリクエストが正常に通らないという事象が起きました。
まぁ当たり前といえば当たり前ですが、iOSのAFNetworkingなんかはその辺をよしなにやってくれるので、ちょっと面食らったという話です。

だったらURL作るときに自分でやってあげましょうねということで、Androidで文字列をURLエンコードする方法を調べました。
java.net.URLEncoderというクラスがあるようで、

String encodedString = URLEncoder.encode("おすし", "UTF-8");

とやってあげるだけでエンコードで来てしまいます。

iOSのURLエンコードには結構があったりするのですが、URLEncoder はどうなのかというと*-_エンコードしてくれないようなので、自分で対応してねとのことでした。

Androidのmenu itemのtextColor

「の」ばっかり続く文章はアホっぽく見えるわけですが、Androidアプリをつくっていて、menu itemのtextColorを変えたかったのでメモです。

結論のみ。android:itemTextAppearanceをオーバライドしてあげましょということみたいです。

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <item name="android:itemTextAppearance">@style/MenuTextAppearance</item>
</style>

<style name="MenuTextAppearance" parent="@android:style/TextAppearance.Widget.IconMenu.Item">
  <item name="android:textColor">@color/text_black</item>
</style>

このstylesあたりがまだマスターしきれてない感じあるので頑張りたい

AndroidのWebViewでJavaScriptが動かない

グッドモーニング。しののめです。

掲題の件ですが、セキュリティ対策でデフォルトでJavaScriptの実行が無効になっている模様です。
コイツをむりくり有効にするには

mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);        
mWebView.loadUrl("http://some-awesome-web-page~~~~");

上記コードの2行目 setJavaScriptEnabled(true) してあげると無事JavaScriptを実行することができるようになります。
このコードを書くと「XSS脆弱性を仕込む可能性があるから注意してね〜」とAndroid Studioさんが警告してくれますので、心当たりがある方は注意してくださいまし

Xcodeでターゲットを複数設定してそれぞれにcocoapodsを適用させる

備忘録として。 私のために誰かのために。

Xcodeではプロジェクトにターゲットを追加していくことができますが、全てのターゲットで同じライブラリ郡を使いたいみたいなシーンはよくありそうです。

が、ターゲットを追加して諸々の設定をしていざビルド!とするとライブラリが読み込めません。 そんな時はここを設定したら解決しましたよ〜というメモです。

Xcodeでターゲットのページではなく「プロジェクトのページ」を開いてinfoConfigurationsDebugReleaseにそれぞれPods.debugPods.releaseが設定されているか確認しましょう。

ただターゲットを追加するだけではここがNoneになっていると思われます。これでcocoapodsを利用してインストールしたライブラリ群を利用できるようになります。

ちなみに、cocoapodsの設定は色んな所にあるので(もちろん追加するターゲットの性質にもよりますが)、同じような設定で利用したい場合は追加よりもベースのターゲットをduplicateして変更箇所を変えていったほうがスムーズかもしれません。

AppleMusicはもしかしてすごくいいかもしれない

AppleMusic

2015年7月1日から始まったApple Musicですが、これもしかしてすごくよいかもーと思いました。

最近日本でもAWAとか、LINE MUSICとか、ストリーミング配信系のサービス界隈が賑わっておりまして、AppleMusicもそんなサービスです。

www.apple.com

awa.fm

music.line.me

料金体系

AppleMusicが他のサービスと比べて良い!ということを言いたいわけではないのですが、まぁ名前が出てきましたし一応各サービスの料金体系を書いてみます。機能的な違いとかは自分で調べて下さい(なげやり)

サービス 料金 対応端末
MUSIC 980円/月 (最初の3ヶ月間無料) Apple製品全般・Windows(2015年秋にAndroidにも対応予定)
AWA Liteプラン 380円/月・Premium Plan 1,080円/月 iOS/Android
LINE MUSIC ベーシックプラン 500円/月・プレミアムプラン 1,080円/月 (2015年8月9日まで無料) iOS/Android

ちなみにSpotifyは9.99ドル/月です。

AppleMusicはなにがいいの?

自分の環境的にすごくいいなーというところは、AppleのサービスだけあってApple製品とかなり密にインテグレートされているわけです。

私の環境としては、自宅にiMac、持ち歩き用・普段仕事用にMacBook Air、携帯はiPhone 6 Plus、あとiPadももってるよーという感じで、Apple信者ばりにAppleデバイスに囲まれています。
そんな感じでスーパー囲い込まれているわけですが、Apple IDひとつで全デバイスにシームレスに同期できるというのは素晴らしく良い所です。

仕事中を含むパソコンつけている時はだいたい音楽を流しています。シチュエーションによってiPhoneで聞いたりMacで聞いたりするので「この曲きこう!」と思った時に聞きたい方に楽曲が入ってないとかなり切ない気持ちになるんですね。
iPodを使っていた時に、出先で「あ!楽曲同期してくるの忘れた!!」ってよくなったじゃないですか。アレです。
なので自分のマシンに入ってる楽曲たちは綺麗に同期されていてほしいわけです。しかも勝手に。

iTunesMatch

というわけで、昨年始まったiTunesクラウド同期サービスiTunes Match(3,980円/年)を契約して利用していました。
これも自分にとってすごい便利で、そもそもiPhoneとかMacBook Airってすぐ保存領域いっぱいになっちゃうのでたくさん楽曲をマシンに入れておけないんですよ。自分の場合、楽曲全部で70GBくらいあるので、そもそも64GBのiPhone買ったとしても全部はいらないわけです。なので、データはiMac全て入っています。
それらをクラウドに置いといて聞きたいときにだけストリーミング・またはダウンロードして聞けるというのはかなり重宝していました。同期漏れとかもなくなりましたし。 これに年間3,980円(ひとつきあたり約332円)を安いととるか高いととるかはあなた次第です…

AppleMusicいざ。

これAWAもLINE MUSICも使ってないのでその他のサービスがどうかはわからないのですが、ビックリしたのですが、AppleMusicを利用して曲を聞いていて、このアルバムいいな~とか思ったら

Music.app

この「+」ボタンをクリックするとマイミュージックに追加され、

iTunes

MaciTunesのミュージックの所に反映されます。うん!これこれ!
うん!これこれ!

そして右っちょに雲のマークが有るということは楽曲はダウンロードできるようようです。(まだ試してない)
一度ダウンロードしてしまえばネット環境ないところでも聞けますね。

これちょっと感激してしまいまして、2秒で契約しようと決心してしまいました。

そしてiTunes Matchも契約してると自分がiTunesMatchにあげている楽曲も一緒くたにマイミュージックに表示されるので、自分のライブラリがドンドン拡張されていきます…

ちなみに、Appleによると

Q. Apple MusicはiTunes Matchと連係しますか?
A. はい。Apple MusicとiTunes Matchはそれぞれが独立したものですが、補完的な関係にあります。

だそうです。確かに補完的ですな。

とういこうとで、とりあえずはiTunes MatchとAppleMusicをどっちも契約して使っていこうと思います。

AppleMusicおすすめな人

  • 音楽好きで色んな音楽を聞いてみたい・聞いてみたいアーティストがたくさんいるけどお金が…><な人
  • Apple製品たくさん持ってる人

たぶん注意しないといけないところ

AppleMusicにかぎらずストリーミング配信サービス全部そうですが、長時間利用する時はWiFi環境下で利用しないと通信制限かかっちゃうよというところです。
あとは当たり前ですが地球上全てのアーティストがいるわけではないので、自分が聞きたい曲全て聞けるとも限りません。

画面が回転するとFragmentが初期化されて困る問題

Androidアプリ開発については結構初心者なんですが、Androidアプリって画面が回転するとActivityが再生成されちゃうんですね。

その時、ActivityにくっついてるFragmentがもつ変数とかが全部初期化されてしまってヌルポで落ちるみたいな現象に直面しました。

この手の問題は結構みんな通る道らしく、ぐぐってみるとsetRetainInstance(true)しようよ!って記事が沢山出てきました。

もちろんどういうふうに実装してるのかによると思うんですが、私の環境だとこれだけだと治りませんでした。

というのも、下記のようにActivity側のonCreate()でFragmentを追加してたんですが

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  FragmentManager manager = getFragmentManager();
  Fragment fragment = OsushiFragment.newInstance();
  FragmentTransaction fragmentTransaction = manager.beginTransaction();
  fragmentTransaction.replace(android.R.id.content, fragment);
  fragmentTransaction.commit();
}

よく考えたら、Activityが再生性されるときもonCreateを通るのだから、ここでFragment初期化する処理自分で書いてるぞ!!ってことで、以下のようにsavedInstanceStateがnullかどうかのチェックをカチこんで、2回目からは初期化されないようにしたらうまくいきましたとさ。

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
    FragmentManager manager = getFragmentManager();
    Fragment fragment = OsushiFragment.newInstance();
    FragmentTransaction fragmentTransaction = manager.beginTransaction();
    fragmentTransaction.replace(android.R.id.content, fragment);
    fragmentTransaction.commit();
  }
}

ActiveRecordでidがないテーブルにデータを保存しようとすると"nil is not a symbol"とか言われる

すんげハマったのでめも。

背景

create_join_tableでつくった中間テーブルのデータを更新したくて、中間テーブル用のモデルからsave!とかupdate!とかしようとしたわけです。

たとえば、 下記の用にOsushiクラスとNetaクラス、そして中間テーブル用のNetaOsushiクラスがあるとします。

class Osushi < ActiveRecord::Base
  has_many :neta_osushi
end

class Neta < ActiveRecord::Base
  has_many :neta_osushi
end

class NetaOsushi < ActiveRecord::Base
  belongs_to :osushi
  belongs_to :neta
end

このNetaOsushiクラスのmigrationクラスは以下のようになるでしょう。

class CreateJoinTableNetaOsushi < ActiveRecord::Migration
  def change
    create_join_table :neta, :osushi do |t|
      t.index :neta_id
      t.index :osushi_id
      t.timestamps
    end
  end
end

で、大人の事情でこのクラスのデータを更新しないといけなくなった場合に、

neta_osushi = NetaOsushi.find_by(neta_id: neta_id, osushi_id: osushi_id)
#
# 某かの代入などの処理
#
neta_osushi.save!

とかすると、nil is not a symbol とかすごい剣幕で怒られてしまい

ヒヤシンス!!!

nil is not a symbol…!!!」

とみおちゃんばりの剣幕で困り果ててしまいました。

解決方法

さてこれかなりドンピシャなQiitaの記事を発見したので御覧ください。

qiita.com

まさにこの状況ですなー。 ということで、複合主キーを設定しましょう。

まずは、複合主キーを扱うために、composite_primary_keysというgemを入れましょう。

github.com

Gemfileに下記一行追加してbundle installします。

gem 'composite_primary_keys', '~> 8.0.0'

ちなみにお使いのActiveRecordのバージョンによってインストールするバージョンも違うので、詳しくはcomposite_primary_keysのリポジトリのREADMEを御覧ください。
ちなみに8.xはActiveRecord4.2.x用です。

そんで、neta_osushiテーブルにunique indexをはります。

class AddIdnexToNetaOsushi < ActiveRecord::Migration
  def change    
    add_index :neta_osushi, [:neta_id, :osushi_id], unique: true, name: 'composite_index'
  end
end

最後に、モデル側で、こいつらがprimary keyだよ〜と教えてあげます。ここは、primary_keyではなく、primary_keys複数なので注意。

class NetaOsushi < ActiveRecord::Base

  self.primary_keys = :neta_id, :osushi_id

  belongs_to :osushi
  belongs_to :neta

end

これで往年の悩みは解決されました。

ゆるしてヒヤシンス!!! ゆるしてヒヤシンス