ユウの小屋

PCの更新内容やSLPでの活動、開発したもの等をupしていきます

簡単なAndroidアプリの開発

はじめに

この記事は、SLP KBIT Advent Calendar 2015の19日目です。

今年9月、私はインターンシップに行き、そこで初めてAndroidアプリを開発しました。

その後、Twitterアプリ開発や某講義の課題など、色々とアプリを開発しています。

ところで、SLP内では、「Androidアプリを開発してます!」という人が、それほど多くないような気がします。

そこで、この記事では、簡単なAndroidアプリの開発手順を説明していき、少しでも興味を持ってもらいたいと思います。

 

開発環境

Android Studio 1.5

JDK 1.8.0_66

Android 5.0.2 (デバッグ用)

 

プロジェクトの作成

まず、アプリ開発のためのプロジェクトを作成します。

ここでアプリ名、対応するAndroidのバージョン、作成するテンプレートを決定します。

対応するAndroidのバージョンは、Android 4.0.3を最小とします。

これにより、現在Google Play Storeにアクセスしているデバイスのうち、94%がこれから作成するアプリを利用できます。

f:id:Yuu-glassdog:20151219134048p:plain

テンプレートの中にはGoogleマップやログイン画面もありますが、今回は空のテンプレートを使用します。

f:id:Yuu-glassdog:20151219133650p:plain

 

Viewの作成

Androidアプリの基本構造は、ViewとActivityから成ります。

Viewはアプリで使用するボタンなどの部品と、そのレイアウトの情報です。

ここで、使用する部品を決め、配置する場所を設定します。

Activityはアプリで表示される画面です。ここにViewを配置し、画面を表示します。

また、ボタンを押した際の処理など、アプリの挙動もここで記述します。

 

まず、Viewから作成します。

各部品は、左のpaletteからドラッグアンドドロップで設置します。

部品を設置すると、そのコードが自動でファイルに記述されます。

表示やサイズを変更したい場合は、コードを編集するか、右のPropertiesを変更します。

f:id:Yuu-glassdog:20151219141301p:plain

作成したファイル activity_main.xml の内容は、以下の通りです。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.splitcost.MainActivity" >

<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="31dp" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Money"
android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge" />

<EditText
android:id="@+id/etxtMoney"
android:layout_width="170dp"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="9" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/yen"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>

<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/linearLayout1"
android:layout_alignParentTop="true" >

<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/numPeople"
android:textAppearance="?android:attr/textAppearanceLarge" />

<EditText
android:id="@+id/etxtNum"
android:layout_width="170dp"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="9" >

<requestFocus />
</EditText>

<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/people"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>

<TextView
android:id="@+id/txtPerOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_marginTop="49dp"
android:text="@string/oneMoney"
android:textAppearance="?android:attr/textAppearanceLarge" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/txtPerOne"
android:layout_below="@+id/txtPerOne" >

<TextView
android:id="@+id/txtOneMoney"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/result"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />

<TextView
android:id="@+id/txtYen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/yen"
android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

<Button
android:id="@+id/button1"
android:layout_width="130dp"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/txtPerOne"
android:layout_below="@+id/linearLayout1"
android:layout_marginTop="28dp"
android:text="@string/calc" />

<Button
android:id="@+id/button2"
android:layout_width="130dp"
android:layout_height="wrap_content"
android:layout_above="@+id/txtPerOne"
android:layout_alignParentRight="true"
android:text="@string/reset" />

</RelativeLayout>

Activityの作成

 次に、Activityを作成します。

 Activityでは、まずViewを参照して、画面に部品を設置していきます。

その後、ボタンの処理を記述すると、アプリは完成です。

作成したファイル MainActivity.java の内容は、以下の通りです。

package com.example.splitcost;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

EditText etxtNum; // 人数
EditText etxtMoney; // 金額
TextView txtOneMoney; // 計算結果
TextView txtYen; // "円"

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Viewをセット
setContentView(R.layout.activity_main);
// Viewの要素を参照
Button btn1 = (Button)findViewById(R.id.button1);
Button btn2 = (Button)findViewById(R.id.button2);
txtOneMoney = (TextView)findViewById(R.id.txtOneMoney);
txtYen = (TextView)findViewById(R.id.txtYen);
etxtNum = (EditText)findViewById(R.id.etxtNum);
etxtMoney = (EditText)findViewById(R.id.etxtMoney);

// 計算ボタンの処理
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// フォーム入力を取得
String strNum = etxtNum.getText().toString();
String strMoney = etxtMoney.getText().toString();
// フォームのどちらかが空の場合
if ( strNum.equals("") || strMoney.equals("") ) {
// アラートを表示
AlertDialog.Builder dlg1;
dlg1 = new AlertDialog.Builder(MainActivity.this);
dlg1.setTitle("エラー");
dlg1.setMessage("人数と金額 両方を入力してください.");
dlg1.setPositiveButton("OK", null);
dlg1.show();
return;
} else {
// 整数変換
int num = Integer.parseInt(strNum);
int money = Integer.parseInt(strMoney);
// 人数が0人の場合
if (num == 0) {
// アラートを表示
AlertDialog.Builder dlg2;
dlg2 = new AlertDialog.Builder(MainActivity.this);
dlg2.setTitle("エラー");
dlg2.setMessage("人数は1人以上にしてください.");
dlg2.setPositiveButton("OK", null);
dlg2.show();
// 人数 > 金額の場合
} else if (num > money) {
// アラートを表示
AlertDialog.Builder dlg3;
dlg3 = new AlertDialog.Builder(MainActivity.this);
dlg3.setTitle("エラー");
dlg3.setMessage("金額は人数以上にしてください.");
dlg3.setPositiveButton("OK", null);
dlg3.show();
// 正常な入力の場合
} else {
// 金額を計算して値をセット
int result = money / num;
txtOneMoney.setText(Integer.toString(result));
// 計算結果を描画
txtOneMoney.setVisibility(View.VISIBLE);
txtYen.setVisibility(View.VISIBLE);
}
}
}
});

// リセットボタンの処理
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// フォームと計算結果をリセット
etxtNum.setText("");
etxtMoney.setText("");
txtOneMoney.setText(getResources().getText(R.string.result));
}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

実行

いよいよ、アプリを実行します。

アプリの実行はエミュレータか、スマートフォンで行うことができます。

今回は、スマートフォン(Android 5.0.2)で実行します。

 

アプリを起動し、人数と金額を入力すると、一人当たりの金額を出力できました。

f:id:Yuu-glassdog:20151219144611p:plain

 

不正な入力を行うと、アラートが表示されました。

f:id:Yuu-glassdog:20151219144757p:plain

 

おわりに

以上が、Androidアプリ開発の大まかな手順です。

実際は、ページ移動やデータベースの利用など、この他にも様々な機能を実装することができます。

少しでも興味を持った人は、ぜひ Android Studio をインストールして、アプリ開発をやってみてください。

 

今回作成したアプリは、GitHub上で公開しています。

github.com

Twitterアプリ作成中

夏季インターンシップで作成していたTwitterアプリ。

細々とローカルで更新していたのですが、本日GitHubで公開しました。

github.com

 

現在、実装している機能は以下の通り。

・アカウント認証

・タイムライン表示

・タイムライン更新

・ツイート

・リツイート

・画像表示(作成中、バグあり)

 

今後、お気に入り機能やトレンド表示機能も実装したいと思います。

 

アプリ作成の際、下記のサイトを参考にしました。

qiita.com

zshのプロンプトにGitのブランチ名を表示

Gitを用いて開発を行う際、いちいち「git branch」を叩いて現在のブランチを調べるのが面倒だと感じました。

そこで、.zshrcに下記のコードを記述。

autoload -Uz vcs_info
zstyle ':vcs_info:*' formats '[%b]'
zstyle ':vcs_info:*' actionformats '[%b|%a]'
precmd () {
psvar=()
LANG=en_US.UTF-8 vcs_info
[[ -n "$vcs_info_msg_0_" ]] && psvar[1]="$vcs_info_msg_0_"
}
RPROMPT="%1(v|%F{green}%1v%f|)"

 

すると、右側のプロンプトに現在のブランチを表示できるようになりました。

なお、Gitで管理されていないディレクトリにいるときは、この表示はされません。

これで、いちいち「git branch」を叩く必要がなくなりました。

f:id:Yuu-glassdog:20151110174058p:plain

 

.zshrcの編集時、この記事を参考にしたのでリンクを貼っておきます。

mollifier.hatenablog.com

GitHubのリポジトリにパスワード無しでアクセス

GitHubをいじっていたら、リモートにpushするたびパスワード入力を求められることに違和感を覚えました。

公開鍵をGitに登録しているのに、何故パスワード入力をする必要があるのか。

 

調べてみると、どうもローカル側で必要な設定をしていなかった様子。

 

そこで、下記のサイトを参考にリモートのURLを変更。

また、global設定にsshを使うよう書き込み。

結果、パスワードを入力せずにpushできるようになりました。

qiita.com

 

公開鍵を作成してGitに登録する方法についても、一応リンクを貼っておきます。

qiita.com

仮想環境でサーバ構築、ニュースを見る

個人的な覚え書きです。 

 

◯ 手順

Vagrantで仮想環境構築

② 鯖立て

Ruby Twitter Gemでニュース取得

CGIで表示

 

Vagrantfile

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "centos63"
config.vm.provision :shell, :path => "provision.sh"
config.vm.network :private_network, ip: "192.168.33.10"
config.ssh.username = 'root'
config.ssh.password = 'vagrant'
config.ssh.insert_key = 'true'
end

 

provision.sh

sudo yum -y install httpd
sudo service httpd start
sudo chkconfig httpd on

 

# vagrant up

仮想のCent6.3が立つ。

このとき、provisionで自動鯖立て。

 

# service iptables stop
# chkconfig iptables off

iptablesを無効化。

 再起動しても、無効化されるようにしておく。

 

# getenforce
# emacs /etc/selinux/config
SELINUX=disabled

SELinuxの状態確認。

Enforcing なら有効。/etc/selinux/config で上記の内容を加える。

Disabled なら無効状態。問題無し。

 

#  emacs /var/www/html/index.html
<h1>Hello,World!</h1>

テストページを作成。

ブラウザで 192.168.33.10 に行って確認。

 

# ruby -v
# gem -v
# gem list
# gem install rubygems-update
# update_rubygems
# gem -v
# gem list
# gem install twitter
# gem list

RubyとGemのバージョン確認。

rubygems-updateをインストール・実行してgemのアップデート。

その後、gemのtwitterをインストール。

 

# cd /var/www/html
# mkdir Twitter
# chmod 755 Twitter
# cd Twitter
# emacs look_news.rb
# chmod 755 look_news.rb

/var/www/htmlにディレクトリ作成。権限は755にしておく。

その下にRubyプログラム look_news.rb を。こちらも権限は755で。

プログラムは以前の記事のものに、以下を加える。

#!/usr/bin/ruby
require 'cgi'

/* KEY云々とclient = 云々 */

print "Content-type: text/html\n\n"
print "<html>\n<body>\n"

/* ツイート引っ張ってくるとこ */

print "</body>\n</html>\n"

 

# emacs .htaccess

/var/www/html/Twitter.htaccess を作成。

内容は以下の通り。

AddHandler cgi-script .cgi .pl .rb
Options +ExecCGI

 

# emacs /etc/httpd/conf/httpd.conf
AddHandler cgi-script .cgi .rb
<Directory />
Options FollowSymLinks ExecCGI
  AllowOverride None
</Directory>
<Directory "/var/www/html">
Options ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>

/etc/httpd/conf/httpd.conf を弄る。

参照

http://blog.netandfield.com/shar/2009/09/22-403.html

http://www.server-world.info/query?os=CentOS_6&p=httpd&f=3

 

# service httpd restart

鯖を再起動して設定反映。

ブラウザで 192.168.33.10/Twitter/look_news.rb に行って確認。

下のようにニュースが見れた。

f:id:Yuu-glassdog:20150709015135p:plain

 

 

Rubyプログラムからニュースを見る

Ruby Twitter Gemのリファレンスから、他人のTwitterアカウントのツイートを表示する方法を見つけたので、それを利用して最新ニュースを見るRubyプログラムを作成しました。

作成したRubyプログラムは、以下の通り。

require 'rubygems'
require 'twitter'

CONSUMER_KEY = " <控えておいた Consumer Key> "
CONSUMER_SECRET = " <控えておいた Consumer Key Secret> "
ACCESS_TOKEN_KEY = " <控えておいた Access Token> "
ACCESS_TOKEN_SECRET = " <控えておいた Access Token Secret> "

Twitter.configure do |config|
config.consumer_key = CONSUMER_KEY
config.consumer_secret = CONSUMER_SECRET
config.access_token = ACCESS_TOKEN_KEY
config.access_token_secret = ACCESS_TOKEN_SECRET
end

client.user_timeline(" <適当なニュース発信アカウントID> ").take(5).collect do |tweet|
puts "\033[36;1m@#{tweet.user.screen_name}\033[0m"
puts "#{tweet.text}"
puts ""
end

このプログラムは任意のアカウントのタイムラインから、最新5件のツイートを表示するものです。そのため、参照するアカウントのリツイートによって、他のアカウントのツイートが表示されることもあります。

 

今回のプログラム作成にあたって、以下のページを参考にしました。

http://route477.net/w/RubyTwitterJa.html

Rubyプログラムからツイート検索を行う

任意のキーワードを入力し、それを含むツイートを抽出するRubyプログラムを作成しました。

作成したプログラムは、以下の通り。

require 'rubygems'
require 'twitter'

CONSUMER_KEY = " <控えておいた Consumer Key> "
CONSUMER_SECRET = " <控えておいた Consumer Key Secret> "
ACCESS_TOKEN_KEY = " <控えておいた Access Token> "
ACCESS_TOKEN_SECRET = " <控えておいた Access Token Secret> "

Twitter.configure do |config|
config.consumer_key = CONSUMER_KEY
config.consumer_secret = CONSUMER_SECRET
config.access_token = ACCESS_TOKEN_KEY
config.access_token_secret = ACCESS_TOKEN_SECRET
end

puts "-----search-----"
target = gets.chomp

client.search(target, :count => 5, :result_type => "recent").take(5).collect do |tweet|
puts "\033[36;1m@#{tweet.user.screen_name}\033[0m"
puts "#{tweet.text}"
puts "\n"
end

今回は、ツイートを5件抽出して出力するようにしました。

作成時に、以下のページを参考にしました。


sferik/twitter · GitHub