2014年10月29日水曜日

Android SDK Content Loader 0%

ecipseで開発している人なら一度は出たことがあるバグではないでしょうか。発生するたびに検索するのが面倒なので解決方法を記載。海外サイトでもよく引っかかるのでついでに英語も。

環境

  • windows7

日本語

eclipseのバグで発生するAndroid SDK Content Loader 0%。cleanとかやっても復活しないときは以下の方法をやってみること

  1. ./androidフォルダへ
  2. cacheフォルダ削除
  3. ddms.cfgファイルを削除
  4. eclipse再起動
  5. 復活

English

if your eclipse occured Android SDK Content Loader 0%, you should action next step.

  1. move to ./android folder
  2. delete cache folder
  3. delete ddms.cfg
  4. reboot eclipse
  5. you feel happy!

android studioの正式リリース版はまだかなあ...

以上

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

knife solo Net::SSH::AuthenticationFailed on AWS LINUX

環境

  • aws linux
  • chefDK 0.3.0

awsでデフォルトユーザー(ec2-user)のままknife soloを実行したらNet::SSH::AuthenticationFailedエラーが発生。
原因はawsでデフォルト作成された秘密鍵のパスワードがわからないから。
インスタンス作成時に自動生成される秘密鍵はパスワードなしで作成されているわけではないってことかな?

解決するにはknife cookをするときに秘密鍵を指定してやればよい。


  knife solo prepare -i ~最初に貰った秘密鍵 ec2-user@vvvvvvvvvvvvxxxxxxxxx.com
  

上記のようにするといつも通りchefが動作する。

以上

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月28日火曜日

[Berkshelf::APIClient::TimeoutError] Unable to connect to: http://api.berkshelf.com/

vagrantでcentos6.5の環境を構築し、chefDKをinstallしてopscodeからソースを取得しようとしたら題名のエラーが発生した。

環境

  • box centos6.5 on vagrant 1.6.5
  • windows7 & mac Yosemite
  • chefDK 0.3.0

原因はconnection.rbファイルのopen_timeoutの設定時間が短すぎること。どうやらwindowsやmac上のvagrantで実行していると名前解決に時間がかかってしまうらしい。

対処方法は、connection.rbを書き換えるしかないようです。ということでLet's hacking。


  find /. -name connection.rb

  // result...
  /opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/berkshelf-api-client-1.2.0/lib/berkshelf/api_client/connection.rb
  

発見。このconnection.rbを書き換える。

before


  def initialize(url, options = {})
    options         = options.reverse_merge(retries: 3, retry_interval: 0.5,
      open_timeout: 3, timeout: 30)

after


  def initialize(url, options = {})
    options         = options.reverse_merge(retries: 3, retry_interval: 0.5,
      open_timeout: 30, timeout: 30)

保存したらいつものようにberks installをすれば上手くいくはずです。

以上

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月26日日曜日

Swift アプリ作成 基本その1 クラスの作成とUnit test

a swift tourを駆け足で終わらせたので、いよいよSwiftでアプリを作成していきます。
詳しく説明していければいいのですが、swiftで本格的に開発するまで1ヶ月くらいしか勉強期間がないのでそこそこ飛ばしていきます。(他もやること色々あるのです...)

環境

  • xcode6.0.1

最初に作成するアプリはチャットアプリ。Listにコメントをならべる「アレ」です。

プロジェクト作成

object-c時代と変わらないです。
xcode → File → New → Projectでプロジェクト作成。言語だけswiftにします。また今回はmaster detail applicationを利用します。
コードの中を見てみると、objective-cの時とあまり変わってない...。本当に開発効率あがるのでしょうか。

Userオブジェクトの作成

User情報を格納するクラスを作成します。以下の通りです。


import Foundation

class User {
    let id: Int
    var name: String?
    var description: String?

    init(id: Int) {
        self.id = id
    }
    
    convenience init(id: Int, name: String, description: String) {
        self.init(id: id)
        self.name = name
        self.description = description
    }
    
    func displayName() -> String {
        if let name = self.name {
            return name
        }
        return "no name"
    }
    
    func displayDescription() -> String {
        if let description = self.description {
            return description
        }
        return "no description"
    }

}

convenience initは委譲イニシャライザ。要はself.initを中で呼ないといけないってことです。呼ばないとエラーになります。
displayName(),displayDescription()はoptinalのString?をString型で返しています。Optional Bindingで非Optional型に変換(String型ってこと)しています。

Userオブジェクトのテストコードの作成

XCTestCaseを継承して作成します。Quickなるものが熱いらしいが、時間ないしXCTestCaseで十分。


import UIKit
import XCTest

class UserTest: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testDisplayName() {
        var user = User(id: 1)
        XCTAssertEqual(user.displayName(), "no name")
    }
    
    func testDisplayDescription() {
        var user = User(id: 1)
        XCTAssertEqual(user.displayDescription(), "no description")
    }
    
    func testDisplayName_name() {
        var user = User(id: 1, name: "taro", description: "hello")
        XCTAssertEqual(user.displayName(), "taro")
    }
    
    func testDisplayName_description() {
        var user = User(id: 1, name: "taro", description: "hello")
        XCTAssertEqual(user.displayDescription(), "hello")
    }
    
    
}


produce → test で実行。全部うまくいってグリーンになると思います。
しかし相変わらずTestコードの説明をしているサイトが少なくてうんざりしたのは内緒w(テストコードを書くって、ちょっとした習慣なんですけどね。なのにほとんどみんなやらない)

さて、この調子で作成していきます。次はchatクラスを作成します。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Swift 学習チートシート3

Swift 学習メモ3

  • xcode6.0.1

基本知識のまとめ


1.enum
1.1.scalaとほぼ同じ

* apple公式に記載されているself.rawValueはなくなったっぽい

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Fice, Six, Seven, Eight, NIne, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
        case .Ace:
            return "ace"
        case .Jack:
            return "jack"
        case .Queen:
            return "queen"
        default:
            return "ng"
        }
    }
}

let ace = Rank.Ace
ace.toRaw()
ace.simpleDescription()
let two = Rank.Two
two.toRaw()
let jack = Rank.Jack
jack.toRaw()

返り値がintなので、値は順番に割り当てられるようだ。微妙な仕様だ。

1.2.値の自動割当なし

enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func simpleDescription() -> String {
        switch self {
        case .Spades:
            return "Spades"
        case .Hearts:
            return "Hearts"
        default:
            return "ng"
        }
    }
}

let hearts = Suit.Hearts
hearts.simpleDescription()

こっちのほうがしっくりくるし、よく使いそう。

2.struct
classと基本同じ。あんま使わない。

struct Card {
    var rank : Rank
    var suit : Suit
    func simpleDescription() -> String {
        return "rank \(rank.simpleDescription()) , suit\(suit.simpleDescription())"
    }
}

let card = Card(rank: .Three, suit: .Spades)
card.simpleDescription()

class Card2 {
    var rank : Rank
    var suit : Suit
    init(rank: Rank, suit: Suit) {
        self.rank = rank
        self.suit = suit
    }
    
    func simpleDescription() -> String {
        return "rank \(rank.simpleDescription()) , suit\(suit.simpleDescription())"
    }
}

let card2 = Card2(rank: .Three, suit: .Spades)
card.simpleDescription()

クラスの場合はinitがないとコンパイルできない

2.Protocol
クラスやstructを拡張する
objective-cと一緒。rubyのmixinのほうが好み。

protocol ExampleProtocol {
    var simpleDescription: String {get}
    mutating func adjust()
}

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "a vert simple class"
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "adjust"
    }
    
}

var a = SimpleClass()
a.adjust()

mutatingは名前付け。javaのabstructみたいなもんかな。

3.extension
型の拡張
rubyのオープンクラスと同じ。これはrubyより洗練されている

extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}

10.simpleDescription

4.Generics
まんまjava。このサイトではandroidでいつも紹介しているので割愛。

以上でA Swift Tourは終了。複数言語のプログラムを習得していればこのA Swift Tourを終了させればそこそこswiftでプログラムがかけると思います。
appleのLanguage Guideをみるとsubscriptとかclosureについて記載してあるので、使いたいと思う機能を写経しましょう。

というわけで次からは本格的にサンプルアプリの作成をしていきたいと思います。でわ。

ちなみにA Swift Tourはブログ用に写経しながらで5hくらいでした。参考までに。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月25日土曜日

2015年問題から見える日本のIT業界の問題点 その4

人を増やしても問題は解決しない

さて、2015年問題に話を戻そう。
この2015年問題、これは人を増やしても解決しないと思う。どれだけ人を増員しても、結局はヘンテコなシステムが構築され、その保守や改修がビジネスとして続いていくことに異論を挟む人はいないだろう。

そもそも、人を増やせば問題が解決するという考えは、テクノロジーの世界ではあまり良い考えとはいえない。産業時代の考え方だ。
もちろん最低限の人数は必要だが、根本的な問題の解決にはならない。
僕の経験上、問題を解決する優れた方法は「問題を考える時間をもつ」「少数の優秀な人でグループを作る」ということである。

「少数の優秀な人でグループを作る」の効果は、googleやfacebookを見れば明らかだろう。少数で組織やグループを構成するのは情報の共有がしやすいからだ。とはいえ、優秀な人物を集めるには時間がかかる。となると、「問題を考える時間をもつ」ことが重要となる。

問題点は日々、状況によって変化する。今解決できない問題でも、時間が経ち知識が増えると解決することはよくあることだ。例えばある製品を作成することになり、7割の出来で先に進むというのは、製品を世に早く出すという点だけでなく、知識を蓄積するという点でもすぐれた仕事の進め方だ。ただ、このやり方の問題点は、周りがそういった製品を認めてくれる環境にあるかどうかが大きい。僕の経験では、スピード重視のベンチャー企業以外ではあまり良い顔をされない。結局、あれもこれも欲しがるのだ。足し算の仕事をできる人は多いが、引き算の仕事が出来る人は本当に少ない。

「問題を考える時間をもつのが重要」とはいえ、日々仕事に追われるとタスクを消化するだけで精一杯になってしまうのは仕方がないことだ。 redmineのチケットと重要タグのついたメールを見ながら焦る気持ちを抱く感覚が僕にはよくわかる。効率化したタスク管理はストレスの効率化と数値化はしてくれない。責任感の強い人やまじめな人が鬱になるのは、こういった効率化したタスク管理にも原因があるように思う。

また、日々の作業を事務的にタスクをこなすだけではいけない。何度もいうが、タスクが増えたから人を増やそうというのは愚か者の発想だ。
もちろん人を入れることで解決することもある。だが、それは、たまたまその問題が人が足りないのが原因だったからに過ぎない。たいていの原因は異なるところにある。その原因をさぐって解決していく習慣をつけると、仕事は楽になるし、成長出来る。

原因を考え、検証、実行、分析ができる習慣を身につけよう。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Android CI設定 jenkins and Bitbucket and Deploygate

新規AndroidアプリのjenkinsへのCI設定をいつも間違えるので、複数回やらかしたエラーの忘備録。

jenkinsでおこなっていること

  • jenkinsでgitからcloneしてきたソースコードをgradleでビルドしてapkを出力する
  • ビルドして出力されたapkをDeploygateに飛ばす

環境

  • Jenkis
  • Bitbakets or gitHub
  • android studio開発アプリ(gradle build)

よく忘れる環境設定チェックリスト

1.ビルドサーバーのandroidを最新にする

SDKを開発環境と同じように最新にしておかないと失敗するので、開発環境のadkをupdateしたときは注意が必要

2,local.propertiesの配置を忘れる

andoirdアプリの開発では、gitでlocal.propertiesは管理しないのが基本。
なので、最初のgit cloneでソースを持ってきたあと、local.propertiesを設定する必要がある。


cd {project_root}

vi local.properties

sdk.dir=/usr/local/android-sdk-linux

// 権限はjenkins
chown jenkins:jenkins local.properties

3.unable to unlink old 'volley/build/generated/source/buildConfig/debug/com/android/volley/BuildConfig.java' (Permission denied)

上記のエラーはgitの管理ファイルに余計なものを含ませていたため発生。上記の場合は、volleyのbuildファイル以下をgitで管理していたのが原因


volleyのbuild以下を削除しgitにcommit&push。
.gitignoreでvolley/buildも追加する必要がある。

教訓

CI環境も常に改善が必要ということです。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

androidアプリを5.0(Material Design)に対応する その3 Google アナリティクス SDK v4の導入

前回ImageViewでユーザーアイコンの表示を円形に表示させました。
今回はグロースハックのお友達Google アナリティクスです。これも5.0関係ないけど、今丁度僕が実装中なのでついでに記載。

SDK v4からはlibは不要となってgoogle play serviceを導入するだけで動きます。んー、便利!
色々と詰め込みすぎで個人的に不安ですが。。。

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="21"
  • andoid studio 0.8.9

アナリティクスを管理するAnalyticsManagerクラスを作成します。googleのコードを参考にして作成しました。


import android.content.Context;

import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import android.util.Log;


public class AnalyticsManager {

    private static Context sAppContext = null;

    private static Tracker mTracker;
    private final static String TAG = "AnalyticsManager";

    public static synchronized void setTracker(Tracker tracker) {
        mTracker = tracker;
    }

    private static boolean canSend() {
        // We can only send Google Analytics when ALL the following conditions are true:
        //    1. This module has been initialized.
        //    2. The user has accepted the ToS.
        //    3. Analytics is enabled in Settings.
        return sAppContext != null && mTracker != null;
    }

    public static void sendScreenView(String screenName) {
        if (canSend()) {
            mTracker.setScreenName(screenName);
            mTracker.send(new HitBuilders.AppViewBuilder().build());
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Screen View recorded: " + screenName);
            }
        } else {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Screen View NOT recorded (analytics disabled or not ready).");
            }
        }
    }

    public static void sendEvent(String category, String action, String label, long value) {
        if (canSend()) {
            mTracker.send(new HitBuilders.EventBuilder()
                    .setCategory(category)
                    .setAction(action)
                    .setLabel(label)
                    .setValue(value)
                    .build());

            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Event recorded:");
                Log.d(TAG, "\tCategory: " + category);
                Log.d(TAG, "\tAction: " + action);
                Log.d(TAG, "\tLabel: " + label);
                Log.d(TAG, "\tValue: " + value);
            }

        } else {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Analytics event ignored (analytics disabled or not ready).");
            }
        }
    }

    public static void sendEvent(String category, String action, String label) {
        sendEvent(category, action, label, 0);
    }

    public Tracker getTracker() {
        return mTracker;
    }

    public static synchronized void initializeAnalyticsTracker(Context context) {
        sAppContext = context;
        if (mTracker == null) {
            int useProfile;
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Analytics manager using DEBUG ANALYTICS PROFILE.");
                useProfile = R.xml.analytics_debug;
            } else {
                useProfile = R.xml.analytics_release;
            }
            mTracker = GoogleAnalytics.getInstance(context).newTracker(useProfile);
        }
    }

}

あとはコード中で必要な箇所で呼び出すだけです

画面名


        if (!BuildConfig.DEBUG) {
            /* [ANALYTICS:SCREEN]
             * TRIGGER:   View the Login screen.
             * LABEL:     'Login'
             * [/ANALYTICS]
             */
            AnalyticsManager.sendScreenView(SCREEN_LABEL);
        }

activityやFragmentのonCreateで呼びます。

イベント


   
            if (!BuildConfig.DEBUG) {
                /* [ANALYTICS:EVENT]
                 * TRIGGER:   button is pushed.
                 * CATEGORY:  'Show List Detail'
                 * ACTION:    buttonListDetail
                 * LABEL:     visible gone
                 * [/ANALYTICS]
                 * */
                AnalyticsManager.sendEvent("Show List Detail", "buttonListDetail", label, 0L);
            }

button押下時などのアクション時に呼びます。

公式サイトにはApplicationクラスに記述するのがお勧めと記載されていますが、実際はutilとしてAnalyticsManagerクラスをつくっているのがgoogleらしいですねw。 でもこちらの方が使いやすいし、汎用性もあります。debugとreleaseのxmlファイルでの分け方はマネすると便利です。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

android studio androidアプリのデバッグapkとリリースapkを出力する

  • 公開日:2014年10月25日
  • 最終更新日:2016年03月17日

記事概要

android studioでアプリを作成した場合の、gradleを使ったビルドの方法を記載した記事です。

android6.0対応版の記事を記述しました。

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="21"
  • andoid studio 0.8.9
  • windows7

はじめに

android studioでアプリを作成したので、gradleを使ったビルドのメモを残しておきます。
コマンドを叩いてapkを出力できるようにしておくと本当に便利なので、設定することをオススメします。

build.gradle

debugとrelease用のkeystoreファイルが作成してあること前提で話をすすめます。

signingConfigsの設定

signingConfigsはアプリファイル(.apk)を作成するときに必要となるkeystoreの設定します。
debug用や、release用のkeystoreを用意する必要があります。(日本語のコメントはNGらしいなので、下記のままだと利用できません。)

build.gradle

android {
    // something
    signingConfigs {
        debug {
            // debug.keystoreファイルのある場所を設定
            storeFile file("./debug.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
        release {
            // release.keystoreファイルのある場所を設定
            storeFile file("./release.keystore")
            storePassword "releaseandroid"
            keyAlias "releaseandroid"
            keyPassword "releaseandroid"
        }
    }
}

続けてbuildTypesを設定します。

build.gradle

android {
    // something
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            signingConfig signingConfigs.release
            //runProguard false
            //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

上記はproguardを指定していませんが、実際は指定したほうが良いです。signingConfigは必須です。

build.gradle

android {
    // something
    lintOptions {
        abortOnError false
    }
}

総てのlintに対応するのは無理があるので、設定することになると思います。

コマンドラインからビルド

プロジェクトのgradlew.batファイルがあるフォルダまで移動します。

terminal

gradlew.bat build

windowsなのでgradlew.batを使います。
macやlinuxの場合はgradlewにします。
成功すると、build/outputs/フォルダの配下にapkが出力されているはずです。

以上です

PICK UP

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月23日木曜日

androidアプリを5.0(Material Design)に対応する その2 画像を円形にする

前回android5.0のライブラリを導入したので、画面も5.0らしくモダンな画面に変更していきます。
今回はありがちなImageViewでのユーザーアイコンの表示を円形に表示させます。

変更前

変更後

この機能はandroid5.0でなくても導入可能なので、ぜひ導入してみてください。

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="21"
  • andoid studio 0.8.9

ImageViewを継承したBezelImageViewというコードを作成します。googleのコードを参考にしてます。


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * An {@link android.widget.ImageView} that draws its contents inside a mask and draws a border
 * drawable on top. This is useful for applying a beveled look to image contents, but is also
 * flexible enough for use with other desired aesthetics.
 */
public class BezelImageView extends ImageView {
    private Paint mBlackPaint;
    private Paint mMaskedPaint;

    private Rect mBounds;
    private RectF mBoundsF;

    private Drawable mBorderDrawable;
    private Drawable mMaskDrawable;

    private ColorMatrixColorFilter mDesaturateColorFilter;
    private boolean mDesaturateOnPress = false;

    private boolean mCacheValid = false;
    private Bitmap mCacheBitmap;
    private int mCachedWidth;
    private int mCachedHeight;

    public BezelImageView(Context context) {
        this(context, null);
    }

    public BezelImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BezelImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        // Attribute initialization
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezelImageView,
                defStyle, 0);

        mMaskDrawable = a.getDrawable(R.styleable.BezelImageView_maskDrawable);
        if (mMaskDrawable != null) {
            mMaskDrawable.setCallback(this);
        }

        mBorderDrawable = a.getDrawable(R.styleable.BezelImageView_borderDrawable);
        if (mBorderDrawable != null) {
            mBorderDrawable.setCallback(this);
        }

        mDesaturateOnPress = a.getBoolean(R.styleable.BezelImageView_desaturateOnPress,
                mDesaturateOnPress);

        a.recycle();

        // Other initialization
        mBlackPaint = new Paint();
        mBlackPaint.setColor(0xff000000);

        mMaskedPaint = new Paint();
        mMaskedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

        // Always want a cache allocated.
        mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);

        if (mDesaturateOnPress) {
            // Create a desaturate color filter for pressed state.
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            mDesaturateColorFilter = new ColorMatrixColorFilter(cm);
        }
    }

    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        final boolean changed = super.setFrame(l, t, r, b);
        mBounds = new Rect(0, 0, r - l, b - t);
        mBoundsF = new RectF(mBounds);

        if (mBorderDrawable != null) {
            mBorderDrawable.setBounds(mBounds);
        }
        if (mMaskDrawable != null) {
            mMaskDrawable.setBounds(mBounds);
        }

        if (changed) {
            mCacheValid = false;
        }

        return changed;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBounds == null) {
            return;
        }

        int width = mBounds.width();
        int height = mBounds.height();

        if (width == 0 || height == 0) {
            return;
        }

        if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) {
            // Need to redraw the cache
            if (width == mCachedWidth && height == mCachedHeight) {
                // Have a correct-sized bitmap cache already allocated. Just erase it.
                mCacheBitmap.eraseColor(0);
            } else {
                // Allocate a new bitmap with the correct dimensions.
                mCacheBitmap.recycle();
                //noinspection AndroidLintDrawAllocation
                mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                mCachedWidth = width;
                mCachedHeight = height;
            }

            Canvas cacheCanvas = new Canvas(mCacheBitmap);
            if (mMaskDrawable != null) {
                int sc = cacheCanvas.save();
                mMaskDrawable.draw(cacheCanvas);
                mMaskedPaint.setColorFilter((mDesaturateOnPress && isPressed())
                        ? mDesaturateColorFilter : null);
                cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
                super.onDraw(cacheCanvas);
                cacheCanvas.restoreToCount(sc);
            } else if (mDesaturateOnPress && isPressed()) {
                int sc = cacheCanvas.save();
                cacheCanvas.drawRect(0, 0, mCachedWidth, mCachedHeight, mBlackPaint);
                mMaskedPaint.setColorFilter(mDesaturateColorFilter);
                cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
                super.onDraw(cacheCanvas);
                cacheCanvas.restoreToCount(sc);
            } else {
                super.onDraw(cacheCanvas);
            }

            if (mBorderDrawable != null) {
                mBorderDrawable.draw(cacheCanvas);
            }
        }

        // Draw from cache
        canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null);
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        if (mBorderDrawable != null && mBorderDrawable.isStateful()) {
            mBorderDrawable.setState(getDrawableState());
        }
        if (mMaskDrawable != null && mMaskDrawable.isStateful()) {
            mMaskDrawable.setState(getDrawableState());
        }
        if (isDuplicateParentStateEnabled()) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    @Override
    public void invalidateDrawable(Drawable who) {
        if (who == mBorderDrawable || who == mMaskDrawable) {
            invalidate();
        } else {
            super.invalidateDrawable(who);
        }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return who == mBorderDrawable || who == mMaskDrawable || super.verifyDrawable(who);
    }
}

attrs.xml


<resources>

    <declare-styleable name="BezelImageView">
        <attr name="maskDrawable" format="reference" />
        <attr name="borderDrawable" format="reference" />
        <attr name="desaturateOnPress" format="boolean" />
    </declare-styleable>

</resources>

dimens.xml


   
    <dimen name="expert_icon_size">60dp</dimen>

circle_mask.xml


<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#000" />
</shape>

上記で完成。あとはlayoutのxmlに記載するだけです。


    <com.tset.testapp.ui.widget.BezelImageView
        android:id="@+id/image"
        app:maskDrawable="@drawable/circle_mask"
        android:layout_width="@dimen/expert_icon_size"
        android:layout_height="@dimen/expert_icon_size"
        android:scaleType="centerCrop"
        android:layout_marginRight="10dp" />

あとはコンパイルして表示すれば上記の画像のように円形の画像が表示されます。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

androidアプリを5.0に対応する その1 ライブラリの導入

さてさて、android5.0が正式にリリースされました。そして、今回のandroid5.0では、かなりの大幅な変更が行われました。
というわけでさっそく対応しようと思います。対応するアプリは現在4.4.2で作成中のアプリなので、参考になれば幸いです。
せっかくswiftに注力できると思ったのに…。

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="19"
  • andoid studio 0.8.9

gradleを以下のように書き換えます。

Before


apply plugin: 'com.android.application'

android {
    compileSdkVersion 19
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.test.testapp"
        minSdkVersion 14
        targetSdkVersion 19

        testApplicationId "com.test.testapp.test"
        testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
    }

    buildTypes {
        debug {

        }
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile project(':volley')
    compile 'com.android.support:support-v4:20.0.0'
    compile 'com.google.android.gms:play-services:5.0.89'
    compile 'com.google.code.gson:gson:2.3'
    compile files('libs/twitter4j-core-4.0.2.jar')
    androidTestCompile files('libs/espresso-1.1-bundled.jar')
}

After


apply plugin: 'com.android.application'

android {
    // 19 → 21
    compileSdkVersion 21
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.test.testapp"
        minSdkVersion 14
        // 19 → 21
        targetSdkVersion 21

        testApplicationId "com.test.testapp.test"
        testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
    }

    buildTypes {
        debug {

        }
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile project(':volley')
    // 20 → 21
    compile 'com.android.support:support-v4:21.0.0'
    // 6.1にする
    compile 'com.google.android.gms:play-services:6.1.+'
    compile 'com.google.code.gson:gson:2.3'
    compile files('libs/twitter4j-core-4.0.2.jar')
    androidTestCompile files('libs/espresso-1.1-bundled.jar')
    // これが欲しい
    compile 'com.android.support:appcompat-v7:21.0.+'
}


上記のように変更しないと、Attribute "theme" has already been definedやら、android:actionModeShareDrawableやらが発生します。
androidのupdateの弱点は、play-servicesがすぐに対応しなくなることですね。これは本当にやっかいです。

あとはいつものようにbuildをすればOK。テストコードを走らせて、動作確認がうまくいけば問題ないでしょう。

cardViewやRecycleViewあたりは、かなり良さそうなので積極的に利用していきたいですね。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月19日日曜日

Swift 学習チートシート2

Swift 学習メモ2

  • xcode6.0.1

基本知識のまとめ


1.関数
1.1.関数の中で関数を記述して呼び出す。

func returnFifteen() -> Int {
    var y = 10
    func  add() {
        y += 5
    }
    add()
    return y
}

returnFifteen()

1.2
関数を変数に格納して利用する
javaScriptでよく使うパターン

func makeIncrements() -> (Int -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}

var increment = makeIncrements()
increment(1)

* Point
(Int -> Int)
上記はIntで貰った関数をIntで返すという意味。


1.3.1.2を少し複雑にした関数
テストコードも各練習しないとダメだけど、とりあえず関数まで一気につぶす。

func hasAnyMathcers(list: [Int], condition: Int -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    
    return false
}

func lessThanTen(number: Int) -> Bool {
    return number < 10
}

var numbers = [20, 14, 17, 12]
hasAnyMathcers(numbers, lessThanTen)

*list: [Int], condition: Int -> Bool
配列とIntを引数にとってboolを返す関数を引数にとる

1.4.closure
クロージャー。
柔軟だけど、あんまやりすぎると可読性が落ちるので注意。テストコード必須。

var numbers = [20, 14, 17, 12]

let mappednumbers = numbers.map({number in 3 * number})

mappednumbers

ここまでの感想。
よく出来てる言語です。objective-cは極力使わない方向でiosの開発は進めていきたいですね。
あとはscalaでのプロジェクトの経験が凄い生きてるのが驚きです。scalaは流行らないと見切りをつけたんだけど、何の知識が役に立つかわからないもんですねえ。


2.class
javaとかrubyとかscalaのいいとこ取り。

class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A sharp with \(numberOfSides) sides."
    }
}

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

さらに続く

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

Swift 学習チートシート

次のiphoneアプリの開発からはSwiftでということが正式に決まったので学習開始。
ざっと見た感じscalaみたい。scalaはあんま得意じゃないです。playframeworkとか苦労した記憶しか無い。

  • xcode6.0.1

基本知識のまとめ


1.let 定数

let lable = "This width is"

2.var 変数

var test = "test"

3.文字列と数値を+でつなげても、自動で数値がstringには変換されない。
文字列の中で\()を使うことで数値を加えることが可能。

let apples = 3
let appleSummary = "I hava \(apples) apples."

# rubyの式展開にちょっと似ている。
# ruby
ape = 15
puts 'My ape is #{ape}"

4.配列

# 初期化
var shoppingList:[String] = []

型を宣言しないとエラーが発生する
× var shoppingList = []

5. optional
scalaのoptionとほとんど同じ

if文でtrueの場合

var optionalName: String? = "Jone appleseed"
var greeting = "hello"
if let name = optionalName {
    greeting = "HEllo, \(name)"
}

6. switch
型での判断が可能。
僕の中の言語の善し悪しの基準に、プログラム言語はswitchの機能で決まるという勝手な思い込みがあるのですが、ruby > scala > swiftという印象。
かなり高機能です。

var vegitable = "red peper"
switch vegitable
{
case "celery":
    let vagetableComment = "Everything is not good"
case "celery", "bule peper":
    let vagetableComment = "this is great!"
case let x where x.hasPrefix("red"):
    let vagetableComment = "common on"
default:
    let vagetableComment = "Everything is good"
}

whereが良い感じ。

7. func
関数
scalaのtupleみたいな機能が使える。いかにもモダンな言語という印象。

func culcStatisc(scores:[Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    
    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }
    
    return (min, max, sum)
    
}

let statistics = culcStatisc([100, 80, 90, 70])
statistics.min
statistics.sum

続く

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月13日月曜日

android Volleyを使ったエラーハンドリング rails grapeとの連携

またしてもVolleyネタです。今回は通常処理でなくエラーハンドリングの処理の場合を扱います。

環境

  • rails4.1.2 and grape
  • android:minSdkVersion="14"
  • android:targetSdkVersion="19"

ステータスコードを受け取る

volleyは、40Xや50Xのstatus codeを受け取ると、VolleyErrorを受け取るような仕様になっています。
サーバーAPIを使ったandroidの処理では、volleyとrails4.1.2 and grapeの組み合わせでjsonを使うのが一番早く作成できると思います(ただし、学習コストは高めかも)。


                //レスポンス失敗時のリスナー
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        executeVolleyError(error);
                    }
                }){

上記ではexecuteVolleyErrorというメソッドを呼び出しています。これはFragmentの共通処理クラス(親クラス)に記述しています。

executeVolleyErrorメソッド


    /**
     * Get Volley Error
     * @param error
     */
    protected void executeVolleyError(VolleyError error) {
        if (BuildConfig.DEBUG) {
            Log.d(TAG, "error : " + error.getMessage());
            Log.d(TAG, "Status code : " +  error.networkResponse.statusCode);
        }
        if (error != null) {
            if (error.networkResponse == null) {
                Toast toast = Toast.makeText(getActivity().getApplicationContext(), getActivity().getApplicationContext().getResources().getString(R.string.network_error_404), Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
                return;
            }

            // status code 400, status code 404
            if (HttpStatus.SC_BAD_REQUEST == error.networkResponse.statusCode || HttpStatus.SC_NOT_FOUND == error.networkResponse.statusCode) {
                Toast toast = Toast.makeText(getActivity().getApplicationContext(), getActivity().getApplicationContext().getResources().getString(R.string.network_error_404), Toast.LENGTH_LONG);
                toast.setGravity(Gravity.CENTER, 0, 0);
                toast.show();
            // status code 503
            } else if (HttpStatus.SC_SERVICE_UNAVAILABLE == error.networkResponse.statusCode) {
                Intent intent = new Intent(getActivity(), MaintenanceActivity.class);
                startActivity(intent);
                return;
            }
        }
    }

status codeが400(パラメーターエラー)と404(ページエラー)の場合は、エラーメッセージをToastで表示しています。
status codeが503の場合はメンテナンス画面に遷移させています。
当然ですが、各acticityやfragmentにゴリゴリとコピーするのはNGなので共通処理としてまとめましょう。

参考までにrails and grape(サーバーAPI)側のコードを以下に記載します。


  resource 'tests' do
    get '/' do
      return error!(Test.maintenanceJson, 503) if Test.isMaintenance?(params)
      return error!(Test.testParamError, 400) unless Test.checkParameter(params)
      tests = Test.tests(params)
      return Test.testJson(tests, params)
    end
  end

以上

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月7日火曜日

android Volleyを使ったListViewをリファクタリング

さてさて。久しぶりに会社絡み抜きでandroidアプリを作成しているのですが、もうひと踏ん張りで終了しそうです。

というわけで、今回はリファクタリングに焦点を当てます

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="19"

volleyを利用したListViewの画像取得をキャッシュする

volleyはここ半年くらいで利用し始めました。とっても便利なライブラリです。デフォルトでも十分な性能ですが、チューニングするとさらにすばらしいことに!

リファクタリング前
よくありがちなVolleyを使ったListView処理です。


        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            View row = convertView;
            if (row == null) {
                LayoutInflater inflater = getActivity().getLayoutInflater();
                row = inflater.inflate(R.layout.fragment_user_row, parent, false);
            }

            UserPojo userPojo = mViewList.get(position);

            ImageView userImage = (ImageView) row.findViewById(R.id.user_image);
            ImageLoader.ImageListener userImageListener = ImageLoader.getImageListener(userImage, R.drawable.image_loading, R.drawable.no_image);
            userImage.setTag(mImageLoader.get(userPojo.user_image_path, userImageListener));

            TextView userName = (TextView) row.findViewById(R.id.user_name);
            userName.setText(userPojo.user_name);

            TextView startTime = (TextView) row.findViewById(R.id.start_time);
            startTime.setText(userPojo.clime_start_time);

            userPojo = null;

            return row;
        }

上記をViewHolderパターンとCancelRequestパターンを実装して書き換えます。

リファクタリング後


        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            ViewHolder holder;
            if (convertView == null) {
                LayoutInflater inflater = getActivity().getLayoutInflater();
                convertView = inflater.inflate(R.layout.fragment_user_row, parent, false);
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            View row = convertView;
            if (row == null) {
                LayoutInflater inflater = getActivity().getLayoutInflater();
                row = inflater.inflate(R.layout.fragment_user_row, parent, false);
            }

            // リクエストのキャンセル処理
            ImageLoader.ImageContainer imageContainer = (ImageLoader.ImageContainer)holder.userImage.getTag();
            if (imageContainer != null) {
                imageContainer.cancelRequest();
            }

            UserPojo userPojo = mViewList.get(position);

            ImageView userImage = (ImageView) row.findViewById(R.id.user_image);
            ImageLoader.ImageListener userImageListener = ImageLoader.getImageListener(userImage, R.drawable.image_loading, R.drawable.no_image);
            userImage.setTag(mImageLoader.get(userPojo.user_image_path, userImageListener));

            holder.userName.setText(userPojo.user_name);
            holder.startTime.setText(userPojo.start_time);

            return convertView;
        }

        /**
         * View holder pattern
         */
        private class ViewHolder {
            ImageView userImage;
            TextView userName;
            TextView startTime;

            public ViewHolder(View view) {
                this.userImage = (ImageView) view.findViewById(R.id.user_image);
                this.userName = (TextView) view.findViewById(R.id.user_name);
                this.startTime = (TextView) view.findViewById(R.id.start_time);
            }
        }

リストの一行のviewをViewHolderクラスを作ってキャッシュし、Viewの再利用時にImageViewからImageContainerのインスタンスを取得し、リクエストのキャンセルを行っています。

リファクタリング前と比較すると相当軽く、速くなります。

p.s 2014年8月までならこれでリファクタリング終了ですが、android Lが使えるようになると、RecyclerViewを使ってさらに高速化できるようです。これは正式版がリリースされたら説明したいと思います。

参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月4日土曜日

androidアプリ開発テクニックまとめ 画像編その2

前回のandroidアプリ開発テクニックまとめ 画像編その1の続きです。 今回は画像の回転処理についてまとめます。

環境

  • android:minSdkVersion="14"
  • android:targetSdkVersion="19"

画像処理 画像回転対策

androidは端末ごとにデフォルトのカメラが搭載されていますが、残念ながら画像を同じ向きで撮影しません。 例えば、Galaxy系はデフォルトが横ですが、nuxus系は縦になります(機種依存です。)

なので、アプリで全ての端末で画像を同じ向きで表示したい場合には画像の向きを取得する必要があります。 この画像の向きを取得するのにandroidではExifInterfaceというクラスを使います。

このクラスはクラス名の通り、Exif(イグジフと読みます)のタグを取得することができます。 Exif「イグジフ」は、画像に埋め込まれたカメラの機種や撮影時の条件を埋め込んでいるメタデータのことです。

では、以下にコードを記載します。


 /**
  * 画像の回転度を取得
  * @param filePath
  * @return
  */
 public static int getRotateDegree(Context context, Uri uri) {
  int degree = 0;
  try {
   ExifInterface exifInterface = new ExifInterface(getPath(context, uri));
   int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
   if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
    degree = 90;
   } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
    degree = 180;
   } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
    degree = 270;
   }
  } catch (IOException e) {
   degree = -1;
   e.printStackTrace();
  }

  return degree;
 }

 /**
  * 画像ファイルのパスを取得する
  * @param context
  * @param uri
  * @return
  */
 public static String getPath(Context context, Uri uri) {
  if(uri == null)
   return null;

  if(uri.getScheme().equals("file"))
   return uri.getPath();

  ContentResolver contentResolver = context.getContentResolver();
  String[] columns = { MediaStore.Images.Media.DATA };
  Cursor cursor = contentResolver.query(uri, columns, null, null, null);
  cursor.moveToFirst();
  String path = cursor.getString(0);
  cursor.close();
  return path;
 }

上記のようにすることで画像の向きを取得することが可能です。 上記のgetRotateDegreeメソッドで返り値が90, 180, 270の場合は、画像が返り値の度数だけ回転していることを示します。

画像を回転させるにはMatrixクラスを使います。


 /**
  * 画像が回転している場合は、適切に表示できるようなMatrixオブジェクトを返します。
  * 画像の回転が必要ない場合はnullを返す。
  * @param orientation 回転度数
  * @param width1      幅
  * @param height      高さ
  * @return
  */
 public static Matrix getMatrix(int orientation, int width, int height ) {

  Matrix matrix = new Matrix();
  if (orientation == 90) {
   matrix.postTranslate(-width/2,-height/2);
   matrix.postRotate(90f);
   matrix.postTranslate(width/2,height/2);
  } else if (orientation == 180) {
   matrix.postTranslate(-width/2,-height/2);
   matrix.postRotate(180f);
   matrix.postTranslate(width/2,height/2);
  } else if (orientation == 270) {
   matrix.postTranslate(-width/2,-height/2);
   matrix.postRotate(-90f);
   matrix.postTranslate(width/2,height/2);
  } else {
   return null;
  }

  return matrix;
 }

postRotateメソッドで回転度数を設定し、postTranslateメソッドで移動距離を設定しています。
移動→回転→移動と、画像を動かしています。

頭の中だけでイメージしにくい人は、紙に書き出して確かめるか、細かくデバッグして一つ一つのメソッドの動きを確かめてみましょう。 回転をさせる時に中心点をずらしているのがわかると思います。

また、Matrixは画像の拡大や縮小でも利用可能です。Bitmapのdecodeを使う場合がほとんどだと思いますが、Matrixと使い分けると便利です。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月3日金曜日

2014/10月時の最新androidアプリ開発環境を構築

android開発の環境をまとめたので以下に記載します。android studioを使う場合は、最初に設定しておきましょう。のちのちの開発効率に天と地ほどの差がでてきます。 jenkinsなどのCIよりはるかに重要です。

環境

  • windows7
  • android studio v0.8.11

開発環境はandroid studioを利用します。今後、私はeclipseは使用しない方向です。
また、android studioでのandroidの開発環境は半年に一度は見直すとよいでしょう。できれば三か月に一度が理想だと思います。

android studioを最新の環境にupdate

android studioを立ち上げ、最新の環境にupdateします。

  • メニューバー → Help → check for update
  • update and Restart

android studioのメモリサイズを増やす

android studioをダウンロードしてきたばかりの初期設定では、動作が重すぎて使いものになりません。必ずメモリサイズを増やしてください。

  • C:\Users\{users}\AppData\Local\Android\android-studio\bin\studio.exe.vmoptionsをテキストエディタで開く。

-Xms1024m
-Xmx2048m
-XX:MaxPermSize=512m

上記のように値を変更します。マシンスペックに余裕があれば値をもっと増やすことを勧めます。

参考サイト

gradle.propertiesファイルを変更

プロジェクトルートにあるgradle.propertiesを編集します。コピペで良いと思います。


# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Settings specified in this file will override any Gradle settings
# configured through the IDE.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# The Gradle daemon aims to improve the startup and execution time of Gradle.
# When set to true the Gradle daemon is to run the build.
org.gradle.daemon=false

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true

# Enables new incubating mode that makes Gradle selective when configuring projects.
# Only relevant projects are configured which results in faster builds for large multi-projects.
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
org.gradle.configureondemand=true

各設定はここここを参考にしてください。

gradleをオフラインモードに変更

毎回gradleで最新バージョンをチェックしにいくのを省略します。

  • メニューバー → Settings → Gradle
  • offline workをチェック

参考サイト

Logcatを見やすくする

Info を青に,Warning を黄色に,Error を赤にします。

  • メニューバー → Settings → Editor → Colors & Fonts → Android Logcat
  • Save Asで新規にSchemeを作成する。

参考サイト

ひとまずここまで、(多分)続く。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2014年10月2日木曜日

unicornの学習メモ

railsで使用してるunicornのまとめ。毎回毎回調べるのが面倒なので。

環境

  • rails4.1.2 & centos6.5

unicornの起動


bundle exec unicorn_rails -c config/unicorn.rb -E development -D

-Dはデーモンとして起動
-Eは環境
-Cはファイル

unicornの停止


kill -QUIT `cat /tmp/unicorn.pid`

きもい停止方法や...

unicornの起動確認


ps auxf | grep unicorn | grep -v grep

設定ファイルメモ


listen "#{@app_path}/tmp/sockets/unicorn.sock", :backlog => 64
listen 8081, :tcp_nopush => true

listen

http://e-words.jp/w/E383AAE38383E382B9E383B3.html
通信機能を持つソフトウェアが、外部からのアクセスに備えて待機することをリッスンということがある。特に、TCP/IPの通信ができるOS上で動作しているプログラムが、特定のポート番号への接続を待ち受けることをリッスンということが多い。そのようなプログラムのことをリスナー(listener:聞き手、聴取者)ということがある。

backlog

listenで設定可能で、保留中の接続のキューの最大長

以上。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

vagrant by windows

windows環境でvagrnatで新しい環境を作成するたびに、同じエラーをやらかすので、以下に忘備録

環境

  • windows7
  • vagrant1.6.5
vagrant設定ファイル注意点

1. vagrant init {name}の{name}はvagrant box listで表示されるboxでなければならない。


  config.vm.box = "centos65-x86_64"

上記の設定が重要。boxがないbox名を指定すると落ちる。

2. エンコーディングはUTF-8に設定せよ!


  Encoding.default_external = 'UTF-8'

上記の設定がないと、vagrant内のコマンドでrubyなどのscript言語を実行すると落ちることがある。

3. GUIを有効にせよ!


  vb.gui = true

上記の設定がないと、VM Bootingで止まることがある。こうなるとOSの再起動が確定的。必ず設定すること。
以上

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...