非常に困っていたが以下のページに助けられる。
どうやらAndroid SDK Build-toolsというツールが新しくビルドに必要になったようである。
こんなのわかるわけない…
せめて自動でインストールしてほしい。
まるで古いPCのアドベンチャーゲームをやらされているような感覚である。 そして、後日Nexus7でもやられてしまった。
関連記事
非常に困っていたが以下のページに助けられる。
どうやらAndroid SDK Build-toolsというツールが新しくビルドに必要になったようである。
こんなのわかるわけない…
せめて自動でインストールしてほしい。
まるで古いPCのアドベンチャーゲームをやらされているような感覚である。 そして、後日Nexus7でもやられてしまった。
関連記事
<!-- 色(color)でmyBackgroundを指定する --> <myapp.MyView android:id="@+id/myview" android:layout_width="wrap_content" android:layout_height="wrap_content" myapp:myBackground="#ffff0000" /> <!-- イメージ(drawable)でmyBackgroundを指定する --> <myapp.MyView android:id="@+id/myview" android:layout_width="wrap_content" android:layout_height="wrap_content" myapp:myBackground="@drawable/bg" />
こんなときはまず attr.xmlでは以下のようにreferenceとcolorの属性として定義する。
<resources>
<declare-styleable name="MyView">
<attr name="myBackground" format="reference|color"/>
</declare-styleable>
</resources>
自作ViewのJava側ではDrawableとして受け取り、背景色を設定したいviewにsetBackgrund()で設定する。 colorもDrawableで受けることができ、背景色として設定できるようだ。 この方法でよいのか公式なドキュメントを確認できていないが問題なく動いているようである。
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
Drawable myBackground = a.getDrawable(R.styleable.MyView_myBackground);
if (myBackground != null) {
myView.setBackgroundDrawable(myBackground);
}
}
ちなみに、AttributeSet.getColor()で受けると以下のようなエラーが出る。
背景色を設定できるようにする場合は特に理由がなければDrawableで受けるようにしておいたほうが無難だろう。
Caused by: android.view.InflateException: Binary XML file line #35: Error inflating class myapp.MyView
at android.view.LayoutInflater.createView(LayoutInflater.java:613)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:270)
at android.app.Activity.setContentView(Activity.java:1881)
at myapp.MyActivity.onCreate(MyActivity.java:58)
at android.app.Activity.performCreate(Activity.java:5104)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
... 11 more
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
at android.view.LayoutInflater.createView(LayoutInflater.java:587)
... 24 more
Caused by: android.content.res.Resources$NotFoundException: File res/drawable-hdpi/bg.png from drawable
resource ID #0x7f020011: .xml extension required
at android.content.res.Resources.loadColorStateList(Resources.java:2094)
at android.content.res.TypedArray.getColor(TypedArray.java:319)
at myapp.SampleQueryView.(SampleQueryView.java:54)
... 27 more
Callback URLを使わずお手軽にすませる方法を使った。 この場合はTwitterログインの後にPIN番号が画面に表示されるので、それを手で入力して認証を完了する。 大まかな手順は次のようである。
今回紹介するコードはAndroidアプリつぶマップで使用しているので、 どのように動くか興味ある方はインストールしてもらえるとよいかと思う。
public class TwitterTest {
private static final String CONSUMER_KEY = "アプリに発行されたConsumer Key";
private static final String CONSUMER_SECRET = "アプリに発行されたConsumer Secret";
private Twitter twitter;
private RequestToken requestToken;
public String requestToken() {
// インスタンスの初期化
twitter = TwitterFactory.getSingleton();
// Twitterに登録したアプリのConsumer key と Consumer secretを設定
twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
// RequestTokenトークン要求
// 認証ページのURLを返すのでWebViewで表示しユーザーにログインしてもらう
requestToken = twitter.getOAuthRequestToken();
return requestToken.getAuthorizationURL();
}
// Accessトークン取得。引数にWebで表示されたPINを入れる。
// 認証済みのTwitterインスタンスを返す
public Twitter getAccessToken(String pin) throws TwitterException {
if (requestToken == null) return false;
// RequestTokenとPINよりAccessトークン取得
AccessToken _accessToken = twitter.getOAuthAccessToken(requestToken, pin);
return twitter;
}
}
まず、TwitterにRequestTokenトークン要求する。ラッパークラスのrequestToken()メソッドを呼び出す。
TwitterTest t = new TwitterTest(); String url = t.requestToken();
メソッド呼び出しの結果、認証のためのTwitterへのログインページURLが返されるのでこのURLをWebViewに表示する。 以下のような画面が開く。同じ画面の上部にはPIN番号を入力するためのEditTextを配置した。
ログインページでユーザーがログインしてアプリを許可するとTwitterがPIN番号を発行する。 画面表示されたPIN番号をユーザーに入力してもらう。
入力されたPINを引数にラッパークラスのgetAccessToken()メソッドを呼び出すことで認証が完了する。
String pin = "ユーザー入力のPIN番号"; Twitter twitter = t.getAccessToken(pin);
メソッドの返り値である認証済みTwitterインスタンスを使ってツイート取得や検索ができる。 以下は検索の例である。
Query q = new Query();
q.setQuery("キーワード");
QueryResult qr = twitter.search(q);
皆さんもぜひ試してみてください。
その後の調査で分かったのだが、MySQLではNOT NULLなTIMESTAMP型の列にNULLを書き込むと現在時刻に置き換えられるという仕様がありそれを利用することで、一応自動で付与するということもできるようだ。
以下のようなテーブル定義として、ts1に行の作成日時、ts2に行の更新日時を入れることとする。
CREATE TABLE t3 ( rid INTEGER, txt VARCHAR(20), ts1 TIMESTAMP DEFAULT 0, ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
INSERT時にts1にはNULL値を書き込むことで書き込みの発生した現在時刻が自動で入る。
mysql> INSERT INTO t3 (rid,txt,ts1) VALUES(1,'aaa',NULL);
Query OK, 1 row affected (0.08 sec)
mysql> INSERT INTO t3 (rid,txt,ts1) VALUES(2,'bbb',NULL);
Query OK, 1 row affected (0.09 sec)
mysql> SELECT * FROM t3;
+------+------+---------------------+---------------------+
| rid | txt | ts1 | ts2 |
+------+------+---------------------+---------------------+
| 1 | aaa | 2013-04-23 16:21:44 | 2013-04-23 16:21:44 |
| 2 | bbb | 2013-04-23 16:21:44 | 2013-04-23 16:21:44 |
+------+------+---------------------+---------------------+
2 rows in set (0.00 sec)
UPDATE時にはts1には値を書き込まないようにする。このようにすることでts1の日時は更新されず、行が作成された日時を示すようになる。
mysql> UPDATE t3 SET txt='zzz' WHERE rid=1;
Query OK, 1 row affected (0.10 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM t3;
+------+------+---------------------+---------------------+
| rid | txt | ts1 | ts2 |
+------+------+---------------------+---------------------+
| 1 | zzz | 2013-04-23 16:21:44 | 2013-04-23 16:21:49 |
| 2 | bbb | 2013-04-23 16:21:44 | 2013-04-23 16:21:44 |
+------+------+---------------------+---------------------+
2 rows in set (0.00 sec)
まあ、でもINSERT時にNULLを指定して書き込まないといけないので、ここに現在時刻を指定するようにしてもプログラムの質としてはあまり変わらないような気がする。 むしろその方がトリッキーでなくわかりやすいかも。