Twitterクライアント製作記その3

ふぁぼった時に星を付けれるようになった.

どうやら,公式RTされてきたものに対してのtwitter4j.Status#isFavorited()はなんかちょっと特殊だった.

Twitter#createFavorite(long id)で指定されたIDのツイートをふぁぼるんだけど,いくらふぁぼっても公式RTの場合は

getHomeTimeline()でそのツイートを取得しなおしても,status,retweetedStatusどちらもisFavorited()でfalseが返ってくるので,どうやって公式RTをふぁぼったときに星を付けられるのかわからなかったけど解決できたのでメモ.

Twitter#createFavorite(long id)は戻り値としてtwitter4j.Statusが返ってくるので,返ってきたstatusを使って処理すれば良い.

ふぁぼに成功した場合,返ってきたstatusと,retweetedStatusはisFavorited()でどちらもtrueを返す.

ArrayAdapterの中にある元のツイートの場所を,mAdapter.position(oldStatus);でもして引っ張ってきて,remove(oldStatus)して,insert(position,newStatus);とすればよい.

星をつける部分は,ArrayAdapter的な自前クラスの部分で,isFavorited()がtrueを返すときに星のvisibilityをView.VISIBLEに,falseのときはView.GONEにすればおk

抜粋

twitter4j.Status oldStatus, newStatus;
twitter4j.Twitter mTwitter;

//oldStatusはなんとかして持ってくる
//mTwitterはなんとかしてfactoryからインスタンスを作る

try {
	newStatus = mTwitter.createFavorite(status.getId());
} catch (TwitterException e) {
	e.printStackTrace();
}
if (newStatus != null) {
	int pos = mAdapter.getPosition(oldStatus);//元のツイートの位置を得る
	mAdapter.remove(oldStatus);//消す
	mAdapter.insert(newStatus, pos);//挿入する
	mAdapter.notifyDatasetChanged();//ListViewに通知してViewの更新
}

カスタムArrayAdapter(抜粋)

public class TweetStatusAdapter extends ArrayAdapter<twitter4j.Status> {
	private static LayoutInflater mInflater;

	public TweetStatusAdapter(Context context) {
		super(context, android.R.layout.simple_list_item_1);
		mInflater = (LayoutInflater) context
				.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Status item = getItem(position);

		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.list_item_tweet, null);
		}

		//他にも色々やるけどね.

		ImageView favIcon = (ImageView)convertView.findViewById(R.id.fav_icon);

		if (item.isFavorited()){
			favicon.setVisibility(View.VISIBLE);
		} else {
			favicon.setVisibility(View.GONE);
		}

		return convertView;
	}
}

 

それにしても,公式RTをふぁぼってもgetHomeTimeline()やgetMentionsTimeline()で得られるstatusがisFavorited()でfalse返すってTwitterさんなんでなのよ…

今日できたこと

  • リストの情報(id, name)を保存して,毎回起動時にリスト情報を取得するために通信しないようにした.
  • 通信する必要が有るときは出来る限りAsyncTaskを使用するようにした(Android3.0以上だと,メインスレッドから通信するとNetworkOnMainThreadExceptionという例外を投げる)
  • Android4.2でもOAuthコールバック時にちゃんと起動するようになった
すぐ出来そうなこと
  • リストを選択して表示
早く実装したいこと
  • 会話を表示
出来れば実装したいこと
  • ユーザー詳細画面
    • フォロー,フォロー解除,R4Sとか
    • ツイート,フォロー/フォロワー表示とか
  • 複数アカウント対応
    • 切り替えはシームレスに行いたい.
    • 別アカウントのリストがずらっと並んだら面白いかなって.
    • ツイート時にアカウントを選択,リプライ時は自動で,みたいな.
    • 複数アカウントのタイムラインを混ぜて表示できたら面白いかも
  • カラーテーマ
    • 最低限白いのと黒いのは用意したいよね

Twitterクライアント製作記その2

出来たこと

  • リストビューが空のときに表示を変えた(ListView#setEmptyView())
  • リストビューの一番下が見えた時にツイートを読み込むようにした(ListView#setFooterView())
  • 認証アカウントの全リストのフラグメントを作成&ViewPagerで表示.スワイプで移動するのは辛い.
  • グラデーションよりものっぺりした方がナウいのでタイルっぽいデザインに,背景をグレーに,他の色はだいたいGoogleのDeveloperサイトに載ってる色にした.
  • 取得時すでにふぁぼっていたツイートには星をつけた.(リツイートだった場合はなぜか判別できないため星を付けれない)
  • お気に入りツイート一覧を表示

ツイートを取得して表示するための基底クラス(抽象クラス)を作成し,これを継承したクラスでリストだったりメンションだったりタイムラインだったりの動作を実装することで,かなり楽に機能を実装できるようになった.

ふぁぼった時,リツイートしたときに,そのツイートにアイコンを付けるようにしたいんだけど,色々スパゲティ状態で辛い.

そして何より,リツイートをふぁぼっていても,リツイートとして表示しているときはなぜか判別が出来ない.

status.isFavorited()でも,status.getRetweetStatus().isFavorited()でもfalseという謎.

getFavorites()で得られたツイートは,status.isFavorites()はtrueになるのになぜなんだ…!

会話を表示するアクティビティと,ユーザーの情報を表示するアクティビティまで出来たらコードごと公開するよ.

Twitterクライアントっぽいもの製作記 その1

Shooting Starっぽいクライアントが作りたいんだ…!ただ,それだけっ…!

今日までにできていること

  • 認証
  • HomeTimelineの取得,表示
  • MentionsTimelineの取得,表示
  • Statusのアップデート
  • 引っ張って更新,引っ張って古いツイートの取得
今日やったこと
  • タイムラインの色分け+グラデーション
  • リプライ,リツイート,ふぁぼ,本文に含まれているリンクにジャンプ
タイムラインの色分け部分はちょっと汚い実装になった気がする.ユーザー名よりユーザーIDで判定したほうが良さげ.

はやくリストを選択して表示できるようにしたい.ListViewが空のときはタップして更新できるようにしたい.

AndroidNDKで作成されるネイティブコードの最適化

APP_CFLAGS := -O2 -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -fPIC -march=armv7-a

Application.mkに上記の内容を追記すると,浮動小数点演算が高速化される.

  • O2は言わずもがなの最適化オプション
  • mcpu=cortex-a8でCPUの指定
  • fPICで静的ライブラリの最適化

かな.間違ってるかも.

入力ノード数3,隠れノード数10*2層,出力ノード数1のニューラルネットバックプロパゲーションで,6種類の教師信号を50000回学習するのにかかった時間が,最適化なしは約20秒,最適化ありだと約4秒になった.すごい.

参考

Android NDKのMakefile最適化オプション

EclipseでデバッグするときSTLコンテナの中身を整形して表示

C++でプログラミングをしていて,デバッグするときにgdbを使えばいいんですけど使い方がいまいちよくわからないのでEclipseを使ってデバッグしたらGUIだし見やすくて操作もしやすくていいかなと思っていたらとんでもない罠があった.

STLコンテナの中身がカオス!

絶対綺麗に表示できるようなプラグイン的Somethingがあるはずだと思い調査.

一応公式に書いてあった http://wiki.eclipse.org/CDT/User/FAQ#How_can_I_inspect_the_contents_of_STL_containers.3F

GDB用のSTLサポートライブラリ的なものをダウンロード

 svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python

または,http://sourceware.org/gdb/wiki/STLSupport からSTLSupportToolを適当なディレクトリにダウンロードして展開

gdbinitファイルを適当な場所に作成

python
import sys
sys.path.insert(0, '/home/maude/gdb_printers/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end

Eclipseでgdbinitの場所を指定.

Window -> preferences -> C/C++ -> Debug -> GDB

参考

Haskellで遊べるようになるまでに打ち込んだコマンド(Xubuntu13.04)

たしかこんなかんじでコマンド打ち込んだ気がする。

sudo apt-get install ghc ghc-prof #コンパイラと何か
sudo apt-get install cabal-install cabal-debian #Haskell用パッケージマネージャ?
sudo apt-get install freeglut3-dev #GLUT OpenGL用の何か
cabal update
cabal install -p GLUT

これでたぶんHaskellOpenGLGLUTが使えるようになるはず。

NDKを使うとどんくらい速くなるのか試す

とても実装が簡単なフィボナッチ数列の第N項を求めるだけの関数を使って,NDKを使った場合と使わなかった場合でどんくらい差が出るのか試した.

NDKを使う手順

  1. Androidプロジェクトの作成
  2. 右クリックして,AndroidTools->Add Native Support
  3. .javaファイルの方に,native指定子を付けてメソッドを宣言
  4. プロジェクトのビルド(これをしないと.classファイルがないと怒られる)
  5. jni以下にヘッダファイルを生成(javahを使う)
  6. 生成されたヘッダから宣言部分をコピペしてcppファイルに実装
前回も書いたけどこういう感じでNDKを使用します.

fibonacci

Androidバイトコードの方はこっち

private long fibo(int n) {
	if (n < 3) {
		return 1;
	}
	return fibo(n-1) + fibo(n-2);
}

ネイティブコードの方はこっち

private native long fiboCpp(int n);//宣言
static {
	System.loadLibrary("fibo");//読み込み
}
#include <jni.h>
#include "fibo.hpp"

long fibo( int n ) {
	if ( n < 3 ) {
		return 1;
	}
	return fibo(n-1) + fibo(n-2);
}

JNIEXPORT jlong JNICALL Java_com_example_hellondk_MainActivity_fiboCpp
  (JNIEnv *env, jobject obj, jint n) {
	return fibo( n );
}

ボタンを押したらスタートして,実行が終わったらTextViewに実行時間を表示するようにした.

実行結果

大体10倍くらいネイティブコードの方が速かった.

考察

やっぱ機械語は速いんですねー.

AsyncTaskを使って,onPreExecute()で開始時間を測り,onPostExecute()で終了時間を測った場合は,Nを小さくした場合でも10ms前後の時間がかかった

開始時間と終了時間の計測を,doInBaskground()内で行った場合は,Nが小さいとどちらの場合も0msになったので,メソッドを呼び出す分のロスだったのかなーと思われる.

また,Nの値にかかわらず実行時間の振れ幅がかなり大きいのも気になった.ガベージコレクションか,それとも他のプロセスが優先して実行されたのか.よくわからない.

実行結果に振れ幅が大きかったので,もっと大量にデータが欲しかったんだけど,ボタン押して画面で確認するのが辛いので諦めた.

_人人人人人人人人人人人人人人人人_
> GUIで操作しようとしたのが悪い <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

何回か試行してそのデータをグラフとして表示とかできるようにしたい…

コードはhttps://github.com/crakaC/NDK_sampleにおいているので煮るなり焼くなりしてください.