phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

【Android】 CSVファイルを読み込んでパースする

Androidで初期データなどCSVファイルを処理したい場合がある。
その時は、CSVファイルをassetsと呼ばれるフォルダに置き、それを読み込んでパースを行う。
assetsフォルダはプロジェクトの一番上に作成する。
assetsフォルダへのアクセスはAssetManagerを通じて行う。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Map;
import java.util.StringTokenizer;

import android.content.Context;
import android.content.res.AssetManager;

public class CSVParser {

	public static void parse(Context context) {
		// AssetManagerの呼び出し
		AssetManager assetManager = context.getResources().getAssets();
		try {
			// CSVファイルの読み込み
			InputStream is = assetManager.open("data.csv");
			InputStreamReader inputStreamReader = new InputStreamReader(is);
			BufferedReader bufferReader = new BufferedReader(inputStreamReader);
			String line = "";
			while ((line = bufferReader.readLine()) != null) {
				// 各行が","で区切られていて4つの項目があるとする
				StringTokenizer st = new StringTokenizer(line, ",");
				String first = st.nextToken();
				String second = st.nextToken();
				String third = st.nextToken();
				String fourth = st.nextToken();
				
				// 何らかの処理
			}
			bufferReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

【Android】Linuxコマンドの実行

AndroidアプリからLinuxコマンドを実行するにはRuntimeクラスを利用する。

package xxxxxxxxxxxx;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import android.util.Log;

public class CommandExecutor {

	private static boolean isStopProcess = false;

	public static String execCommand(String command) throws IOException {
		isStopProcess = false;

		if (command == null || command.equals("")) {
			return null;
		}
		Runtime runtime = Runtime.getRuntime();
		Process process = runtime.exec(command);
		String result = readInputStream(process.getInputStream());
		if (result == null || result.equals("")) {
			result = readInputStream(process.getErrorStream());
		}

		if (process != null) {
			process.destroy();
		}

		return result;
	}

	private static String readInputStream(InputStream in) throws IOException {
		InputStreamReader inReader;
		BufferedReader bufReader = null;
		StringBuffer output = new StringBuffer();
		try {
			inReader = new InputStreamReader(in);
			bufReader = new BufferedReader(inReader);

			String line;
			while (((line = bufReader.readLine()) != null) && !isStopProcess) {
				output.append(line + "\n");
				Log.d("CommandExe", "output:" + output);
			}

		} finally {
			if (bufReader != null) {
				bufReader.close();
			}

		}

		return output.toString();
	}

	public synchronized static void stopProcess() {
		isStopProcess = true;
	}
}

Runtimeクラスはインスタンスを自由に作ることはできず、getRuntime()というメソッドが用意されている。
getRuntime()で取得したインスタンスに対してexec(String prog)メソッドを実行することでコマンドを実行できる。
返り値としてプロセスが返ってくるので、これを利用して結果を読み込む。
今回は readInputStream(InputStream in)というメソッドを用意して結果を読み込んでいる。
というのもコマンドの実行が成功したときと失敗したときで結果が取得できるInputStreamが異なるためである。

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);

//コマンド実行が成功した場合のInputStream
InputStream in = process.getInputStream();

//コマンド実行が失敗した場合のInputStream
InputStream errorin = process.getErrorStream();

今回は結果が空だったら失敗とみなして、エラーの結果を取得する。

String result = readInputStream(process.getInputStream());
if (result == null || result.equals("")) {
	//コマンド実行失敗
	result = readInputStream(process.getErrorStream());
}

また、コマンド実行をメインスレッドで行うと結果が返ってくるまで画面が止まってしまうので、マルチスレッドでコマンドを実行することを想定している。
例えばlogcatを実行した場合、プロセスを停止させるまでずっと結果を取得し続けてしまう。
今回はisStopProcessというbooleanのフラグを用意し、この値がtrueになったら停止するようにしている。
isStopProcesはsynchronizedなstopProcess()メソッドを他のスレッドから呼ぶことでtrueになり、プロセスを停止できる。

private static boolean isStopProcess = false;

private static String readInputStream(InputStream in) throws IOException {
	InputStreamReader inReader;
	BufferedReader bufReader = null;
	StringBuffer output = new StringBuffer();
	try {
		inReader = new InputStreamReader(in);
		bufReader = new BufferedReader(inReader);

		String line;
		//結果がなくなるかフラグがtrueになったら終了
		while (((line = bufReader.readLine()) != null) && !isStopProcess) {
			output.append(line + "\n");
			Log.d("CommandExe", "output:" + output);
		}

	} finally {
		if (bufReader != null) {
			bufReader.close();
		}

	}

	return output.toString();
}

public synchronized static void stopProcess() {
	//プロセスを停止するフラグをtrueにする
	isStopProcess = true;
}

【Android】 端末にインストールされているパッケージ一覧をadbコマンドで表示

Android端末に入っているパッケージの一覧をadbコマンドで表示できる。

adb shell pm list package 

結果は以下のようになる。

package:com.android.defcontainer
package:com.htc.customappinstaller
package:com.htc.android.qxdm2sd
package:com.htc.sense.ime.langpack.xest
package:com.htc.dnatransfer.legacy
package:com.htc.sense.ime
package:com.htc.sense.ime.langpack.xtha
package:com.android.phone
package:io.appium.unlock
package:com.htc.widget.profile
package:com.htc.fm
package:com.mobilesuica.msb.android
package:jp.co.jreast
package:com.yodobashi.iShop
package:com.android.bluetooth
package:com.android.providers.calendar
package:com.example.berserkdroid
package:com.htc.android.mail
package:com.htc.drive.activator
package:com.htc.stock
package:com.htc.simplelauncher
package:com.htc.provider.CustomizationSe
package:com.htc.checkinprovider
package:com.ichi2.anki
package:com.inventec.dreye.htc
package:com.htc.rosiewidgets.datastrip
package:com.htc.htccalendarframework.res
package:com.htc.android.home.res
package:jp.amazon.mShop.android
package:com.htc.sense.ime.langpack.xkaz

【Android】 クリップボードへのコピー

Androidクリップボードにテキストを追加してコピーできるようにするにはClipboardManagerを使う。

ClipboardManagerはAPI 11(~3.0)までで使われていたものとAPI11から推奨となったもので2つある。

// API 10(2.3.*)まで
import android.text.ClipboardManager

ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
clipboardManager.setText("text");

// API 11(3.0)から
import android.content.ClipboardManager

ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText("label", "text"));

API 11からは単にsetText()を呼ぶのではなくClipDataを使用して複雑なデータも扱えるようになった。

ちなみにAP11から推奨となっている方のClipboardManagerををAndroid2.3以下で動かすと下のようなエラーが出てクラッシュする。

E/AndroidRuntime(3072): FATAL EXCEPTION: main
E/AndroidRuntime(3072): java.lang.NoClassDefFoundError: android.content.ClipboardManager
E/AndroidRuntime(3072): 	at xxx.xxx.xxx(xxx.java:yyy)
E/AndroidRuntime(3072): 	at android.view.View.performClick(View.java:2552)
E/AndroidRuntime(3072): 	at android.view.View$PerformClick.run(View.java:9229)
E/AndroidRuntime(3072): 	at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(3072): 	at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(3072): 	at android.os.Looper.loop(Looper.java:138)
E/AndroidRuntime(3072): 	at android.app.ActivityThread.main(ActivityThread.java:3701)
E/AndroidRuntime(3072): 	at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(3072): 	at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(3072): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
E/AndroidRuntime(3072): 	at com.android.internal.os.ZygoteInit.fmain(ZygoteInit.java:636)
E/AndroidRuntime(3072): 	at dalvik.system.NativeStart.main(Native Method)