Android 文字の縦位置

[Android] 縦位置を中心にする。

<TextView
	android:text="@string/nam_str"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:gravity="center_vertical"
/>

と書いて、位置がー変わらないと嘆いていましたが。

		<LinearLayout
		 android:orientation="horizontal"
		 android:layout_width="fill_parent"
		 android:layout_height="wrap_content"
		 android:gravity="center_vertical"
		 >
    		<TextView
				android:text="@string/nam_str"
				android:layout_width="fill_parent"
				android:layout_height="wrap_content"

			/>
		</LinearLayout>

とするとうまくいきました。

java.util.Timerよりjava.util.concurrent.ScheduledExecutorServiceのほうが柔軟

サービスの中でタイマー処理を入れようとTimerを使ったのですが、停止と再開の処理が難しく例外が多く出ました。Javaの1.5より追加された、concurrentを使うようです。
concurrentのScheduledExecutorServiceを使うと思った操作になりました。

これを使って、ネットワーク接続を監視するサービスを作りました。3GChekerという名前で公開しています。
ソース貼っときます。

package jp.co.acl_inc.G3Checker;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Vibrator;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;


public class ChekerService extends Service{
	private Context context = this;
	private  Timer timer = new Timer(true);
	private final Handler handler = new Handler();
	private ScheduledExecutorService service;
	private ScheduledFuture  future = null;
	/**
	 * サービスをはずすときの処理です。
	 */
	@Override
	public boolean onUnbind(Intent intent) {
		stopSelf();
		service.shutdown();
		return super.onUnbind(intent);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		service.shutdown();
	}

	/**
	 * startServiceでサービスが呼ばれたときに最初に呼ばれる処理です。
	 */
	@Override
	public void onCreate() {
		super.onCreate();
		service = Executors.newSingleThreadScheduledExecutor();
		Log.d("--ACL--", "Start Service On Create");
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return iChekerServiceBinder;
	}
	/**
	 * サービスをバインドします。
	 */
	private final IChekerService.Stub iChekerServiceBinder = new IChekerService.Stub() {
		//チェックサービスをスタートします。
		public void startChecker() throws RemoteException {
			future = service.scheduleAtFixedRate(r, 0, 60 * 1000, TimeUnit.MILLISECONDS);
    		Log.d("--ACL--", "start checker");
		}
		//チェックサービスをストップします(サービスの一時停止)。
		public void stopChecker() throws RemoteException {
			if (future != null) {
				future.cancel(true);
			}
    		Log.d("--ACL--", "stop checker");
		}
	};
	/**
	 * スケジュールタスク
	 */
	Runnable r = new Runnable() {
		@Override
		public void run() {
			handler.post(new Runnable() {
				public void run() {
					myTask();
				}
			});
		}
	};
	/**
	 * タイマータスク
	 */
	private TimerTask timerTask = new TimerTask() {
		@Override
		public void run() {
			handler.post(new Runnable() {
				public void run() {
					myTask();
				}
			});
		}
	};
	/**
	 * タスクの実処理
	 */
	private void myTask() {
		Log.d("--ACL--", "In Run of Service");
        ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = cm.getActiveNetworkInfo();
        TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
        if( ni == null ){
    		Toast.makeText(context, "ネットワークに接続していません。", Toast.LENGTH_SHORT).show();
    		openActivity();
    		Log.d("--ACL--", "Network is null");
    		vibrate();
        } else {
    		Log.d("--ACL--", ni.toString());
        	if (ni.getType() == ConnectivityManager.TYPE_MOBILE) {
	    		if(!ni.isAvailable()) {
		    		Toast.makeText(context, "ネットワークが非活性です。", Toast.LENGTH_SHORT).show();
		    		openActivity();
		    		Log.d("--ACL--", "Not Available");
		    		vibrate();
	    		}
	    		if (!ni.isConnected()) {
		    		Toast.makeText(context, "ネットワークに接続していません。", Toast.LENGTH_SHORT).show();
		    		openActivity();
		    		Log.d("--ACL--", "Not Connected");
		    		vibrate();
	    		}
        	}
    	}
	}
	/**
	 * バイブレーション
	 */
	private void vibrate() {
		Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
		long[] pattern = {1000, 1000, 1000, 1000, 1000, 1000}; 
		vibrator.vibrate(pattern, -1);
	}
	/**
	 * アクティビティを開く
	 */
	private void openActivity() {
		Intent i = new Intent(getApplicationContext(),G3CheckerAvtivity.class);
		i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(i);
	}

}

レイアウトのXMLはよくわからん。

ListViewの下にViewをおこうと思ったのですが、嵌ったので、XMLを晒しおきます。
android:layout_alignParentBottom="true"で下に行くようです。
android:layout_weight="1"を入れないと、右側のボタンが見えなくなります。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/tbackground"
    android:id="@+id/list_linear_tlayout"
	>
	<ListView
		android:layout_height="fill_parent"
		android:layout_width="fill_parent"
		android:id="@+id/tlist"
		android:background="#00000000"
		android:cacheColorHint="#00000000"
		 android:gravity="top"
		>
	</ListView>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <Button android:id="@+id/tweet_btn1"
            android:text="@string/tweet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <EditText android:id="@+id/my_tweet"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:focusable="false"
            android:singleLine="true"
            android:layout_weight="1"/>
        <Button android:id="@+id/tweet_btn2"
            android:text="@string/tweet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</RelativeLayout>

Google グループ
の記事をもとに着信を知るためのプログラムを書いてみました。

以下をActivity内のonCreateなどに

        TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener psListener = new PhoneStateListener() {
	        public void onCallStateChanged(int state, String number) {
	        	switch(state) {
	        	case TelephonyManager.CALL_STATE_RINGING://鳴っている状態
		        	Log.d("--ACL--","Calling!!");
		        	break;
	        	case TelephonyManager.CALL_STATE_OFFHOOK://電話に出た
		        	Log.d("--ACL--","Talking");
		        	break;
	        	case TelephonyManager.CALL_STATE_IDLE://終了
		        	Log.d("--ACL--","End-talking");
		        	break;
	        	}
	        }
        };
        tm.listen(psListener, PhoneStateListener.LISTEN_CALL_STATE);

以下をマニュフェストに

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

分かれば簡単。

AndroidのListViewでWebの画像を表示させる

ListView内にTwiterアイコンを表示させたら、かなり重くなりました。調べてみると、AdapterのgetViewが毎回呼ばれていて、毎回画像をとりに行っていました。
コンストラクタで画像は取得して使いまわすようにしました。コンストラクタ内に例外処理があるのはなんとなくなので、もう少し改良しようと思います。

package jp.co.acl_inc.android.netladio;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class TwitterAdapter extends ArrayAdapter {

	private ArrayList<TwitterStatus> items;
	private LayoutInflater inflater;
	Drawable[] icons;

	/**
	 * コンストラクタ
	 * @param context
	 * @param textViewResourceId
	 * @param items
	 */
	public TwitterAdapter(Context context, int textViewResourceId, ArrayList<TwitterStatus> items) {
		super(context, textViewResourceId, items);
		this.items = items;
		//コンストラクタで画像データをセットする
		icons = new Drawable[items.size()];
		for (int i = 0; i < items.size(); i++) {
			TwitterStatus item  = (TwitterStatus) items.get(i);
			try {
				URL url = new URL(item.getProfileImageUrl());
				icons[i] = Drawable.createFromStream((InputStream)url.getContent(), "");
			} catch (MalformedURLException e) {
				Log.e("--ACL--", e.getMessage());
			} catch (IOException e) {
				Log.e("--ACL--", e.getMessage());
			}
		}
		this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// ビューを受け取る
		View view = convertView;
		if (view == null) {
			// 受け取ったビューがnullなら新しくビューを生成
			view = inflater.inflate(R.layout.tlist_row, null);
		}
		// 表示すべきデータの取得
		TwitterStatus item = (TwitterStatus)items.get(position);
		if (item != null) {
			//ユーザー名
			TextView fromUserTextView = (TextView)view.findViewById(R.id.from_user);
			fromUserTextView.setText(item.getFromUser());
			//テキスト
			TextView textTextView = (TextView)view.findViewById(R.id.text);
			textTextView.setText(item.getText());
			//画像
			ImageView profileImageView = (ImageView)view.findViewById(R.id.prifile_image_url);
			if (icons != null) profileImageView.setImageDrawable(icons[position]);
			//発信時刻
			TextView createAtTextView = (TextView)view.findViewById(R.id.create_at);
			createAtTextView.setText(item.getCreateAt().toLocaleString());
		}
		return view;
	}
}

副題は「終身雇用の幻想」

課長立場にというものに全く興味がなかったのでスルーしてましたが、城さんの「若者はなぜ3年で辞めるのか?」の続編で、筆者の最終回答とのことです。

本書は物語風に進みます。ホチキス止めのような簡単な軽作業しかさせてもらえない一郎。非正規雇用です。彼はいいます「能力で給料に差がつくのは当然だ。でもそもそも難しい仕事を任せてもらえなければそもそも競争にならないじゃないか」
その弟、二郎は正社員になります、「仕事にやりがいとか充実感を求めちゃいけないんだな」と思いながら。
二人産んだらあとが無い(会社にいられなくなる)花子も出てきます。
一生ひらの40代健一も出てきますし、仕事のない窓際部長も出てきます。
ありそうな光景が続きます。末は博士かフリーターかと、普通に考えたらブラックジョークのような日常が描画されます。

筆者は日本は階級社会であると言います。これは面白い視点だと思いました。皆が自分たちを守るために、格差が固定し階級化してきたのです。一億総中流社会という時代から階級社会までに20年ちょっと。格差社会ではなく階級社会。格差ならば諦めなければ少しは格差を埋められそうですが、階級は全て横でやり取りするので、縦の流れがなくなります。

なるほど、昨日友達の結婚式で箱根に行きましたが、結構賑わっていました。週末箱根で過ごせる階級と、家でひきこもる階級。2000円の天丼を食べる階級、500円の天丼を食べる階級。

格差社会でたまにでもささやかな贅沢が出来る状態であればよかったのですが、階級社会ではそういったものも減っていくのかもしれません。

国家公務員や大企業の社員、定年を迎えた団塊の世代は、底辺の階級(若者)から見たら貴族階級なのかもしれません。階級は固定されています。GDPが増えていかない限り、若者が年を取っても、今の子供達が年を取っても、底辺階級のままでしょう。

今の日本がフランス革命前夜のフランスとダブってきました。

搾取される若者が取っている作戦は合法非合法は問わず、以下のとおりです。

  1. ひきこもり作戦(働かなければ誰からも搾取されない)
  2. オレオレ詐欺作戦(非合法な世代間の所得移転)
  3. 非婚、少子化(人工の逆ピラミッドを加速させリセットを早める)

個々人は自分たちの都合で動いていると思いますが、合理的な戦略であるとも言えます。国債が国民の資産を超える日まで遠くありません。それまでもっといろいろなことが起きてくるでしょう。

話がそれましたが、本書は日本の階級を定義した意味で名書と言えます。

副題は「なぜ10年前の35歳より年収が200万円も低いのか」

なかなか衝撃的な本でした。私は高学歴ワーキングプアのくちなので、まぁ飢え死にしないで研究できればよしとしようと思っていた方ですが、普通に働いている人もなかなか大変なのですね。

10年前と言えば2000年頃、このころも97年の山一證券の破綻など景気は悪かったような気がします。確かにITバブル等はありましたが世相は暗かったような。35歳というとおそらく社会人になったのが、95,96年ごろでしょう。就職難の中を頑張って生きて、10年経ったら200万円減とは報われません。

この10年好景気は何度かあったわけですが、着実に35歳世代は貧しくなってきたということでしょう。35歳世代は団塊Jr.世代ですのでボリュームゾーンで目立つのかもしれませんが、現在の25歳世代が35歳世代になったときに状況が良くなっているかというとむしろ悪くなっているように思います。そうすると、35歳世代以下の人々は皆、報われない世代と言う事になります。

デフレの影響で200万円収入が下がったという考え方もできると思いますが、その上の世代の年功序列賃金を守るために35歳世代にしわ寄せが行ったとも考えられます。日本は「親父」の雇用を極力守ることにより、今の家族の崩壊を防いできたのかもしれません。そのため、将来の家族を持つ世代にしわ寄せが行っていると考えられます。

そうして守った「親父」世代が続々と定年し、年金生活に入ります。恐ろしいことに子供の出生より、65歳人口が増える割合が多いのです。この人達は国民年金で平均5-6万円程度、厚生年金で16万円程度、企業年金も入れるとJALなどの放送を見ていると40万円以上月にもらうようです。

もちろん一部は積み立ててきた部分もあろうかと思いますが、JAL企業年金など年率4.5%前提という実態と合わない規定であったようです。そんな年金は貰う人は当然積み立てた自分のカネと思っていて、納める方は「世代間の助け合い」「相互補助」と言われて自分は収めています。

そして、新卒の人の手取りより、いや収入より、おやじの年金の方が多い事態が生まれている。働いている人の収入より、働かない人の収入の方が多いのは、私にはブラックジョークにしか思えない。

本書の帯には「収入が伸びない、仕事が見つからない、結婚できない、子供をもてない・・・」と書かれている。本書は35歳世代に対する丁寧なインタビューとアンケート、海外事例から構成されている。最後には提言が書かれているが、その提言が実行されるかは分からない。

もしも本当に年金が「世代間の助け合い」というのであるならば、困っている世代に年金を払うべきではないのではないか。その意味では子ども手当は子供に対する年金であると考えることもできよう。決してバラマキとは言えないのではないだろうか。

いつか行く道と思い皆黙っているのかもしれないが、高齢の人を敬うそんな時代にはもう遠い過去なのかもしれない。