ラベル ソフト開発 の投稿を表示しています。 すべての投稿を表示
ラベル ソフト開発 の投稿を表示しています。 すべての投稿を表示

2013年7月19日金曜日

git HEADとかHEAD^とかHEAD^^とかHEAD^2とかHEAD~とかHEAD~2とか (沢山書いとく)

ふらふら話題が変わって今度はgitかよ!

という感じかもしれませんが。

なんか自分の中で曖昧だったのと、さくっと検索した感じこのポイントで解説されている所が無かったのでまとめておきます。




って感じの時、HEAD^とか^^とか^2とか~とか~~とか~2とかってどれになるのでしょう?

教科書だとこんな感じです


表記意味
^1番目の親
^nn番目の親
~1世代上の親
~nn世代上の親の親

ごめんよく分からなかった。

いや、理解した今はごくまっとうな説明って分かるけど、最初意味分からんかった。

というわけで分かりやすい~の方から解説

HEAD~

「1世代上」なので、上記だとCommit2 or Commit3。
どっち?という話はあるがまあ問題無し

HEAD~2

「2世代上」なので、つまり祖父。上記だとCommit1
特に問題無し

HEAD~~

これは、(HEAD~)~という解釈になる。つまり『「1世代上」の1世代上』なのでこちらもやはり祖父。
上記だとCommit1。
これも特に問題無し。

HEAD^

「1番目の親」。何番目だろうが親なので祖父より上は考えないのが正解。
上記だと例えばCommit2。
まあこれもよくある例。

HEAD^2

「2番目の親」。何番目だろうが祖父より上は考えないので、上記でHEAD^がCommit2ならばHEAD^2がCommit3。
~2と^2は全然意味が違う。

HEAD^^

この表記も良く見る。一見^2と同じかと思うが、これもHEAD~~同様(HEAD^)^という解釈になる。
つまり、『「1番目の親」の1番目の親』。つまり祖父
^^と^2は全然意味が違う。

まとめるとこんな感じ

「~系」






「^系」



まあ、ちゃんと理解してる人には当たり前過ぎる話題かと思いますが、自分みたいな初心者には落とし穴かもしれないのでまとめときました。

今回はオチ無し。

2013年2月19日火曜日

子供向け(大人も可) 迷路ゲーム "KIDZ MAZE" 公開

調子に乗ってもう一つアプリ公開しました

迷路ゲーム KIDZ MAZE


です。

特徴は、このブログのどこかで見た画が使われてるって事でしょうか
タイトルから迷路から、ビットマップは全部、子供の絵をキャプったもので作りました

ザ・親バカアプリ第一弾と言えるでしょう

2013年2月12日火曜日

Android無料版(Free)と有料版(Paid)の作り分け

先の記事で、継承使えば良いんじゃーとか偉そうに言いましたが、
http://developer.android.com/tools/projects/index.html

に下記の記述がありました(汗)
読んでねえ。もちろん読んでねえ。

 If you are creating an application that exists in both free and paid versions. You move the part of the application that is common to both versions into a library project. The two dependent projects, with their different package names, will reference the library project and provide only the difference between the two application versions.

で、肝心のlibrary化はどうやるのか?
Eclipseだと色々と助けてくれると思うので、ここでは敢えてantベースの手順を記載します。
ざっくりとした流れは下記の通り。

  1. ベースとなるプロジェクトを作成。まずはlibrary projectでなくてOK
  2. ベースプロジェクト内で実装、Free/Paid共通の基本機能をもつアプリとして作成し動確します
  3. ベースプロジェクトをlibrary project化
  4. 新たにFreeもしくはPaidのプロジェクトを作成(どちらか、もしくは必要ならば両方)
  5. library projectを参照、継承しFree/Paidのアプリを作成

です。上記でポイントとなる所についてちょっと解説します

■ベースプロジェクト(以下lib project)のlibrary project化

これは非常に簡単です。lib projectのproject.propertiesに下記を追加します

android.library=true

■library projectの参照

作成したFree or Paid版プロジェクト(以後app project)のproject.propertiesを編集し下記を追加します

android.library.reference.1=../path/to/lib-project


パスは相対パス(project.propertiesからのパス)である点に注意

■lib projectを使用する際の注意点

本記事を書いている時点でまだあまり一般的でないと思われる注意点として

「libで生成されるR.idはfinalが付いてない」

という問題があります。
これはどうやら仕様のようです。(http://d.hatena.ne.jp/Kazzz/20111022/p1)

これがどういう事かと言うと、一般的な問題としてR.idをswith/caseの条件として使用できなくなる、という事です。

http://developer.android.com/guide/topics/ui/menus.html

はおもいきりswitch caseで実装してますが・・・

上記の例に逆らって、R.idはswitch/caseの条件に使用しないようにしましょう。つまり上記のURL先にある下記のコードを例に取ると

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);

ではなく

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.new_game) {
        newGame();
        return true;
    } else if (item.getItemId() == R.id.help) {
        showHelp();
        return true;
    } else {
        return super.onOptionsItemSelected(item);
    }

にしておく必要があります。

■lib projectにあるactivityを使い回す

複数のactivityが存在するlib projectをベースにしている場合、lib projectのactivityが明示的intentで他のlib project内のactivityを startActivityしているケースが多いと思います。この場合、このactivityは当然lib project内のactivityを指定してしまいます。この指定される先のactivityをapp projectで上書きしたactivityに置き換えたい場合に登場するのがAndroid.Manifest内のactivity-aliasです。

使い方は簡単で、app projectのAndroid.Manifest内の内に必要なactivityの数だけ下記を追記します



appActivityにlibActivityの名前を付ける、という意味です。

例えばあるlibActivity1がlibActivity2を明示的intentでstartActivityするように実装されているケースにて、起動されるActivityをlibActivity2を継承したappActivity2に差し替えたい場合は、appActivity2にlibActivity2という名前を付けてあげる、というやりかたで解決しているわけです。

■lib project内でGCMとか使ってる場合のtips

GCMでは、ユーザーがGCMBaseIntentServiceを継承し、メッセージを受けるようにGCMIntentServiceを実装するのがパターンです。しかしこのGCMIntentServiceをlib package内で定義した場合でも、GCMは固定的にapp-package.GCMIntentServiceに対して通知してしまいます。

lib-packageのGCMIntentServiceをそのまま使うためには、GCMがlib.package.GCMIntentServiceに対して通知するようにしなくてはなりません。このためには

  • app package内にGCMBroadcastReceiverを継承したAppGCMBroadcastReceiverを作成
  • appプロジェクト以下でAppGCMBroadcastReceiver.javaに下記を実装
        @Override
        protected String getGCMIntentServiceClassName(Context context) {
            return "lib.package.GCMIntentService";
        }
    
  • app packageのAndroid.ManifestにAppGCMBroadcastReceiverを登録(lib packageではcom.google.のGCMBroadcastReceiverを登録しているので、その代わりになる)
    
    

以上で、app projectでもlib.package.GCMIntentServiceにちゃんと通知が行くようになります。

2012年12月23日日曜日

A Simple Table Talk 公開

RailsやらAndroidやら不穏な話を最近してましたが、久々にアプリ公開しました

ごくごくシンプルなチャットアプリ A Simple Table Talk


です。

特徴はとにかくシンプルな事?文字だけのチャットです。

他?

・・・考えときます。

2012年12月17日月曜日

AndroidでSingletonパターンをやりたい


謎の何か。

さて、下記の記事、android開発では基本らしいのですが知らない人はびっくりするんじゃないでしょうか?

http://mobileapplication.blog.fc2.com/blog-entry-2.html
http://mobileapplication.blog.fc2.com/blog-entry-3.html

端的に言うとAndroidではメモリ不足等の場合に、生存中のActivityのメンバ変数が勝手に開放される場合がある、って事ですね。

自分も知らなかったのですが…
Androidアプリを開発したての頃に頻発してた原因不明の例外はこれだったみたいです。

でもまあ、良く見りゃちゃんとDeveloper's Guideにも載ってます。

http://developer.android.com/guide/components/activities.html#SavingActivityState

読んでねぇ。
もちろんそこまで読んでねぇ。
最初に言って欲しいわそれは。

そもそも普通にソフト勉強してくと「変数は値が保証される」って半ば無意識に前提にしちゃうと思うんですが、正直その前提というか価値観が崩れる衝撃でした。おおげさ?

しかしメンバ変数についてはユーザーにコールバックという形で通知が来るので百歩譲って良しとしましょう。(その対応として分かりきった手続きを毎回アプリ設計者に実装させる意図はよく分かりませんが・・・)

しかしstaticに至ってはいつ消去されるかすら分からない模様。
ざ、斬新すぎじゃよ?

これの意味する所は、AndroidアプリでSingletonパターンは使えないって事ですよねそうですよね違いますかね?

Androidアプリでは、オブジェクトの生存を保証するものはActivity、という事だと言えそうです。つまり設計上Sigletonなインスタンスが存在するのであれば、それは常にrunningなActivityから参照されている(かつ適切にonSaveInstanceState()/onRestoreInstanceState()されている)必要があるわけです。

もはやSingleton"パターン"ではないですね…

なお、詳細はDeveloper's Guideを見てもらうのが良いのですが、メンバ変数の退避はBundleインスタンスに対して保存する形を取っています。つまり、基本型(intとか配列とか。Stringも基本みたいなもので)か、ParcelableもしくはSerializableなクラスでないといけません。好き勝手にオリジナリティー溢れるクラスやら作りまくってActivityにぶらさげまくってると破綻するって事になるので注意した方が良いですね。

2012年11月20日火曜日

AndroidでJSON取得

取得できるものがJSON ArrayなのかJSONなのか分かった上で切り替えれば良いのですが、一つの内部関数なんかで処理しちゃいたい場合事ありますよね?(強引)
その場合、下記のような関数を使う事で


Arrayだった場合 : そのままJSONArrayとして取得
Objectだった場合 : 要素として一つだけJSONObjectが含まれたJSONArray
それ以外 : 要素0のJSONArray


として一括でArrayとして扱えます。

private JSONArray convertJSONArray(String jsonString) {
    JSONArray ret=null;
    try {
        ret = new JSONArray(jsonString);
        Log.d(TAG, "convertJSONArray : Array");
        Log.d(TAG, "convertJSONArray : ret = "+ ret.toString());
        return ret;
    } catch (JSONException e) {
        ret = new JSONArray();
        try {
            JSONObject json = new JSONObject(jsonString);
            ret.put(json);
            Log.d(TAG, "convertJSONArray : Object");
        } catch (Exception e1) {
            Log.d(TAG, "convertJSONArray : Fails");
        }
        Log.d(TAG, "convertJSONArray : ret = "+ ret.toString());
        return ret;
    }
}
まあえばって公開するほどのコードでも無いんですが、いちいちArrayとObjectを切り替えるのがコード上面倒だったもんで、ちょっと悩みました。 なのでせっかくなんで公開しておきます。

2012年10月4日木曜日

逃亡編

(例によって絵と本文は関係ありません)
前編: herokuでform_tagの:remote => trueが動かない の続き

結論から行くと、なんとかなりました。
端的に言うと

:remoteの代りにformのactionでjQueryを使用してajaxを実行

です。

はい。逃げました。


そ、Solutionが多数用意されているというのもRailsの柔軟性の高さですね。
とかなんとか。

具体的には

view/layoutで参照されているlayout(一般的にはapplication.html.erb)に下記を定義
var doPost = function (url) {
    $.ajax({
    url: url,
    type: "post",
    data: "comment="+$("#comment").val(),
    dataType: "script"});
};
$("#comment")はjQueryによるSelectorです。
<% form_tag ... %>~<% end %>中に
<%= text_field_tag :comment %>
があれば、id="class"で上記のSelectorは正しく動く、はず。

で、あとは、form_tagのactionから上記のdoPostを呼ぶようにすればOK
<%= form_tag ("javascript: doPost(\"/sessions/\"") do %>
本当は、:remoteと完全に同じ挙動にするためには以下にしたかった

<%= form_tag ('#', :onsubmit => "doPost(\"/sessions/\"); return false;") do %>
でもやっぱり、form_tagが第二引数を取ってくれないので相変わらずエラーになるので逃げた。


逃げるが勝ち

2012年9月13日木曜日

herokuでform_tagの:remote => trueが動かない


(絵と本文はちょっとだけ関係あります。無力感とか)


更新していない間、色々ありまして今はRuby on Railsをherokuで動かしてます
・・・何があったんじゃろか?
で一個どうしても解決できない問題があるのでここに挙げておこうと思います

[現象]

以下のhelperがherokuで正しく動作しない(実行時エラー)
<%= form_tag ('/sessions', :remote => true) do %>
ローカルのrails上では正しく動作している

[エラーの詳細]

% heroku logs
:
2012-09-11T03:50:31+00:00 app[web.1]: ActionView::Template::Error (/app/app/views/tables/_form.html.erb:1: syntax error, unexpected ',', expecting ')'
2012-09-11T03:50:31+00:00 app[web.1]: ...nd=  form_tag ('/sessions', :remote => true) do @output_...
2012-09-11T03:50:31+00:00 app[web.1]: ...                               ^
:
要は第二引数が有ることがダメだと言っているみたい。
一方ローカルでは期待通り下記のように変換され、正しくリクエストが発行できる
<form accept-charset="UTF-8" action="/sessions" data-remote="true" method="post">

[分かっている事]

% bundle status
% heroku run bundle status
の差分は以下の通り。後者は意図通りなので実質bundlerのみ。これはhelperの動作とは関係ないはず・・・
11c11
<   * bundler (1.1.5)
---
>   * bundler (1.2.0)
28a29
>   * pg (0.14.1)
41d41
<   * sqlite3 (1.3.6)

ちなみにheroku側のGemはこんな感じ。Railsは3.2.8なので問題ないはず・・・
* actionmailer (3.2.8)
* actionpack (3.2.8)
* activemodel (3.2.8)
* activerecord (3.2.8)
* activeresource (3.2.8)
* activesupport (3.2.8)
* arel (3.0.2)
* bcrypt-ruby (3.0.1)
* builder (3.0.0)
* bundler (1.2.0)
* coffee-rails (3.2.2)
* coffee-script (2.2.0)
* coffee-script-source (1.3.3)
* commonjs (0.2.6)
* erubis (2.7.0)
* execjs (1.4.0)
* hike (1.2.1)
* i18n (0.6.1)
* journey (1.0.4)
* jquery-rails (2.1.1)
* json (1.7.5)
* less (2.2.1)
* less-rails (2.2.3)
* libv8 (3.3.10.4)
* mail (2.4.4)
* mime-types (1.19)
* multi_json (1.3.6)
* pg (0.14.1)
* polyglot (0.3.3)
* rack (1.4.1)
* rack-cache (1.2)
* rack-ssl (1.3.2)
* rack-test (0.6.1)
* rails (3.2.8)
* railties (3.2.8)
* rake (0.9.2.2)
* rdoc (3.12)
* sass (3.2.1)
* sass-rails (3.2.5)
* sprockets (2.1.3)
* therubyracer (0.10.2)
* thor (0.16.0)
* tilt (1.3.3)
* treetop (1.4.10)
* twitter-bootstrap-rails (2.1.3)
* tzinfo (0.3.33)
* uglifier (1.3.0)


・・・全然分かりません。
じ、次回は解決編じゃぜ?!

2012年8月11日土曜日

ubuntuとかtomcatとかJDBCとかの小ネタ

諸事情によりubuntuでtomcatやらscreenやらJDBCやらいじることになり、その時のメモを公開しまス

ubuntuでssh経由のscreenを使用する


ubuntuではssh接続環境下では、screenは単純には動作しないようです。(12.04LTS)

ncurses-termのインストールが必要になります

$ apt-get screen install
$ apt-get ncurses-term install

これでssh接続下でscreenが実行可能になります

ncurses-termについては特別な設定は不要です
もちろん、.screenrcは適切に作成できている等はできているという前提です


tomcat7の導入

諸々のサイトでは普通に下記で良いとありますが

$ apt-get tomcat7 install

その後、ブラウザから
http://localhost:8080
にアクセスしてインストール成功の画面が出ても、tomcat7の場合は下記を入れないとそれぞれのリンクから先に進めません
というかなぜかこれが書いてある所があまりないようなのでここに記載

$ apt-get install tomcat7-admin
$ apt-get install tomcat7-docs
$ apt-get install tomcat7-examples

tomcatからMySQLへのアクセス

そこら中に説明がありますが、tomcat等からjdbc経由でMySQLにアクセスするためにdriver(com.mysql.jdbc.Driver.jar)が必要です
ただ、servletの場合、javacのclasspathにdriverのパスを指定してもムダです。コンパイルは通るのでブラウザ経由でServletにアクセスはできますが、driverのinstanceを生成するコードが実行されると、そんなクラス知らない、という例外が発生します

ここでは一般のjavaファイルを実行する場合を考えましょう。この場合何らかの外部パッケージを使用している場合は

$ java ~.java -classpath ~.jar

と、JVMに必要なjarファイルのパスを知らせます。これと同じ事でServletの場合は同様にtomcatがcom.mysql.jdbc.Driver.jarにアクセスできないといけません

という事で、正解は必要なファイルをWEB-INF/libに入れる、です
これも書いてある所が意外とすんなり見つからなかったのでここに記載

なお、Ubuntuの場合はSymbolic Linkでも機能します

JDBCのMySQL用DriverのInstance生成

この方法自体はあちこちで説明されています。そこでは呪文のように

Class.forName("com.mysql.jdbc.Driver").newInstance();

って見ますが、これは基本的に動的なクラス名からインスタンスを生成する時に使う方法です

たとえば、

String className = request.getParameter("class");
Class.forName(new String (className)).newInstance();

っていう感じの事をしたい時に使う手法です

本来、このMySQLドライバのインスタンス生成を行うケースではクラス名は分かっているので

new com.mysql.jdbc.Driver();

っていうお馴染みの方法でOK

こちらもなぜかこの事が書いてあるサイトが無いのでムダな抵抗でここに書いておきます

ちなみに、本com.mysql.jdbc.Driverはimportができないようですが、importできないイコールnewできない、ではありません

importは

new java.util.List();



new List();

という様にパッケージ名を省略できるようにするための仕組みです


2012年7月25日水曜日

ソフト開発スキルだけでは何も作れない?

すっかり行かなくなってしまった合コンですが、下記みたいなパターンが定番でした
女の子「何やってるんですかぁ~?」
自分「んぁー、TV?作ってるって感じ?」
女の子「えー、TV、なんか流れてくる感じの組み立てるの?」
自分「いやー、そーいうんじゃなくてソフト作ってます」
女の子「ソフト?」

っていうのがメンドくさくてしまいにはマジメに説明しなくなりましたが、まあ一般的にはソフトって何?っていう人はまだ多いでしょう(うちの嫁とか)

ソフトの事は分かる、という一般的でない人でも、ソフトの定義ってこういうのが主だと思います
  • プログラム言語に精通している(C言語とかJavaとかperlとか)
  • フローチャートとかオブジェクト指向とか
  • デザインパターンとかUMLとか
  • 仕様定義とか要件定義とか
  • 大規模開発とか構成管理ツールとかバグトラッキングツールとか
  • ウォーターフォールとかアジャイルとか
  • サーバとかクライアントとか
まあ業態により色々あると思いますが、ソフト関係者が想像されるのはこの辺なんじゃないでしょうか
という事を踏まえ、先の記事のようにこれからソフトスキルを軸足にして伸ばすべきスキルって何だろう、と考えた時に気づきました


「ソフト開発スキルだけじゃ一人じゃまともなもんなんも作れなくね?」


何らかの組み込みであろうが、PCやスマホのアプリ、はたまたクラウドアプリであろうが、何かしらユーザーを相手に機能するためには、ソフトに加え必ず
  • UIデザイン
  • データそのものとデータ管理方法
の二つが必要になります


まあ絵にするほどのもんでもありませんが。

これって当たり前だと思っている人もいるんだと思いますが、自分的にはちょっとした発見でした。
ソフト関係者でこれを意識している方は意外と少ないんじゃないかなー?

という事もあり、簡単なアイコンくらいなら作成できるようになろう、という事でGIMPの勉強をはじめた、という経緯です。

また、UIやデータハンドリングを考える上で参考になるかなぁという事で、情報デザインの勉強で下記の本を読んだりしています




次はこれにしようかなと





これで「データベースを有効活用しつつ、グラフィックデザインもシャレオツでUIも解りやすい」ナイスアプリが一人でも作れるようになって副収入がっぽがぽだぜ日本の発展に貢献したいとオモイマス

2012年6月23日土曜日

Androidアプリ開発小ネタ




(絵と本文に関係はありません)
ちなみに「これ、羊なの」だ、そうです


さて、Androidアプリの世界では
  • 無償版。Free。機能制限 and 広告有り
  • 有償版。Full機能 and 広告無し
というのは結構定番ですよね

今回は、アプリ開発の観点から、上記をスマートに実現する方法を考えます
(ググっても良いやり方が買いてあるブログ、サイトが見つけられなかったので・・・)

通常、これらのアプリは別アプリとしてMarketに置かれています
よってPackageとしては別になります
そのため物理的に一つのソースコード(.javaファイル)を共通して持つ事はできません。Javaは実装毎に自分がどのパッケージに含まれるのか明記が必要だからです(という理解です)

一方、有償、無償、双方に共通の機能は共通の(ひとつの)実装にしたいと普通は考えます
Java、Android開発の経験が浅かった事もあり、また実質開発終了していたため、以前は真面目に考えずコピーして済ませてしまいました

今回はまだ公開前という事あり、ちゃんと考えてみました

ちなみに現時点ではまだ机上検討レベルで未確認です
実装してみて課題や解法見えたら、またここに追記したいと思っています

ポイントは継承です(今考えるとすげー普通)

その1
  1. 有償版(広告無し)を実装
  2. 無償版は有償版のMainActivityを継承 (importで有償版のパッケージを指定する事で可能になるはず)
  3. 無償版Activityで広告viewの追加およびlistener回りの処理を追加。また機能制限されているものは蓋をする(この仕組みは有償版に入れておく必要あり)
その2
  1. 無償版(広告有り)を実装
  2. その1同様、有償版は無償版のActivityを継承する
  3. 有償版のActivityでは広告表示を停止する。また必要な追加機能等をactivateする(同じく無償版は有償版限定機能も実装しておき、蓋をしておく必要がある)
ただし上記その1、その2では親クラスとなるActivity(およびパッケージ)が、本来そのパッケージには関係の無い機能を(蓋をするなりして)有しているという事になり、デザイン上はあまり好ましく無さそうです(まあ、個人開発のレベルでは問題にならないと思いますが)

よって、理想的には
  1. 無償、有償で共通な機能をcommon packageで実装する
  2. 無償、有償それぞれがcommon packageを継承したactivityを作成
  3. 無償、有償それぞれにそれぞれ必要な機能を追加する
ですね。common packageはいわゆる.apkを生成する必要はなく、未公開という事になります。

まずはこれで今作ってるやつ実装してみます