Android エミュレータのSDカードにファイルを配置する
まずエミュレータにSDカードを作成します。
エクリプスのメニューより「ウィンドウ」→「AVDマネージャー」を選択します。
開いたダイアログよりSDカードを作成するエミュレータを選択し「編集」ボタンをクリックします。
SDカードに512MのSDカードを作成しました。
「AVDの編集」をクリックしダイアログを終了します。
SDカードが作成できたら「開始」ボタンでエミュレータを起動します。
エミュレータが起動したらエクリプスのメニューより「ウィンドウ」→「パースペクティブを開く」→「その他」→「DDMS」を選択します。
「ファイル・エクスプローラ」タブにsdcardが見えていると思います。
私のエミュレータではmntフォルダの下にsdcardが有りました。
最初はトップ階層のsdcardだと思って「なんでフォルダじゃないんだろう」なんて悩んでしまいました。
情報列の「mnt/sdcard」の意味がわからなかった・・・
右上の「pull a file」ボタンと[push a file」ボタンでSDカードにファイルを配置したり取り出したりできます。
私の環境では日本語名のファイルは「push a file」ボタンで配置できませんでした。
DDMSでファイルを配置できない場合は、コマンドプロンプトから以下のコマンドを入力します。
※ファイルを配置するには
>adb push C:\Sample.txt /sdcard/
adb push <PCにあるファイル> <デバイスのフォルダ>
※ファイルを取り出すには
adb pull <デバイスファイル名> <PCのファイル名>
Android TabActivityとTabHostを使用してTab画面を表示する
2012/11/19 追記
TabHostを使用する方法はAndroid 3.0 以降は非推奨となりました。
TabHostを使用せずにタブ画面を表示する方法はコチラ
Android ActionBarとFragmentを使用してTab画面を表示する(Android 4.0以上)
Android ActionBarとFragmentを使用してTab画面を表示する(Android 2.x)
むかし2年程前にタブメニューについて調べたんです。コレ→「Android タブ画面を表示する」 今回タブを使おうと思って昔の記事を読んでみたんですが・・・全然わかんないわぁ(;´д`) 自分で読んでも何を書いてるのかわかんないのに、二人の人が役にたったとリアクションしてくれてます。ゴメンナサイ 結局、私の役にはたたなかったので、ほかの人のブログを参考にしました。 自分の調べた事をメモるブログなのに意味ないしっ(>_<) 気を取り直して、再度調べた事をまとめておきます。 タブメニューを作成するにはTabHostウィジェットを使用します。 ActivityにTabHostを配置し、ActivityのonCreate()でTabHostにタブを追加します。 各タブをクリックしたときに表示するコンテンツですが、以下の3通りがあるようです。
TabHostを使用する方法はAndroid 3.0 以降は非推奨となりました。
TabHostを使用せずにタブ画面を表示する方法はコチラ
Android ActionBarとFragmentを使用してTab画面を表示する(Android 4.0以上)
Android ActionBarとFragmentを使用してTab画面を表示する(Android 2.x)
むかし2年程前にタブメニューについて調べたんです。コレ→「Android タブ画面を表示する」 今回タブを使おうと思って昔の記事を読んでみたんですが・・・全然わかんないわぁ(;´д`) 自分で読んでも何を書いてるのかわかんないのに、二人の人が役にたったとリアクションしてくれてます。ゴメンナサイ 結局、私の役にはたたなかったので、ほかの人のブログを参考にしました。 自分の調べた事をメモるブログなのに意味ないしっ(>_<) 気を取り直して、再度調べた事をまとめておきます。 タブメニューを作成するにはTabHostウィジェットを使用します。 ActivityにTabHostを配置し、ActivityのonCreate()でTabHostにタブを追加します。 各タブをクリックしたときに表示するコンテンツですが、以下の3通りがあるようです。
- TabHostを配置したアクティビティに定義したViewを表示する。
- 他のアクティビティを表示する
- layoutファイルに定義したViewを表示する
TabHostを配置したアクティビティに定義したViewを表示する
ActivityにTabHostを配置します。 アウトラインを見ると以下のようになっていると思います。TabHost(id/tabhost) |--LinearLayout |--TabWidget(id/tabs) |--FrameLayout(id/tabcontent) |--LinearLayout(id/tabs1) |--LinearLayout(id/tabs2) |--LinearLayout(id/tabs3)注意点は以下の3点です。
- TabHostはidがtabhostであること。
- TabWidgetはidがtabsであること。
- FrameLayoutはidがtabcontentであること。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TabHost android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" > </TabWidget> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/tab1" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tabページ1" /> </LinearLayout> <LinearLayout android:id="@+id/tab2" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tabページ2" /> </LinearLayout> <LinearLayout android:id="@+id/tab3" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tabページ3" /> </LinearLayout> </FrameLayout> </LinearLayout> </TabHost> </RelativeLayout>タブ部分に表示するテキストをres/values/strings.xmlに定義します。
<resources> : : <string name="tab1">ページ1</string> <string name="tab2">ページ2</string> <string name="tab3">ページ3</string> </resources>ActivityはTabActivityを継承して作成し、onCreate()でTabHostに各タブを追加していきます。 TabSpec#setIndicator()でタブ部分の文字を指定します。 TabSpec#setContent()でタブをクリックした時に表示するViewのidを指定します。 ここではactivity_main.xmlにある3つのLinearLayoutのidです。 MainActivity.java
public class MainActivity extends TabActivity { private static final String TAB[] = {"tab1", "tab2","tab3" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //TabHostオブジェクト取得 TabHost tabhost = getTabHost(); //Tab1設定 TabSpec tab1 = tabhost.newTabSpec(TAB[0]); tab1.setIndicator(this.getResources().getString(R.string.tab1)); tab1.setContent(R.id.tab1); tabhost.addTab(tab1); //Tab2設定 TabSpec tab2 = tabhost.newTabSpec(TAB[1]); tab2.setIndicator(this.getResources().getString(R.string.tab2)); tab2.setContent(R.id.tab2); tabhost.addTab(tab2); //Tab3設定 TabSpec tab3 = tabhost.newTabSpec(TAB[2]); tab3.setIndicator(this.getResources().getString(R.string.tab3)); tab3.setContent(R.id.tab3); tabhost.addTab(tab3); //初期表示するタブ tabhost.setCurrentTab(0); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
他のアクティビティを表示する
次はタブをクリックした時に表示するコンテンツにActivityを指定する方法です。 まずTabHostを配置したメインとなるアクティビティを1つ作成します。 そしてタブをクリックした時に表示するアクティビティをタブの数だけ作成します。 つまりタブが3つある画面であれば4つのアクティビティを作成することになります。 各タブのコンテンツとなるアクティビティ「Tab1Activity.java」、「Tab2Activity.java」、「Tab3Activity.java」を作成します。 各アクティビティには、それぞれの違いがわかるように適当にウィジェットを配置しておきます。 次にメインとなるActivityを作成します。 こちらは「TabHostを配置したアクティビティに定義したViewを表示する」で作成したMainActivity.javaとほぼ同じです。 違いは、TabSpec#setContent()でアクティビティを指定します。 MainActivity.javapublic class MainActivity extends TabActivity { private static final String TAB[] = {"tab1", "tab2","tab3" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //TabHostオブジェクト取得 TabHost tabhost = getTabHost(); //Tab1設定 TabSpec tab1 = tabhost.newTabSpec(TAB[0]); tab1.setIndicator(this.getResources().getString(R.string.tab1)); tab1.setContent(new Intent().setClass(this, Tab1Activity.class)); tabhost.addTab(tab1); //Tab2設定 TabSpec tab2 = tabhost.newTabSpec(TAB[1]); tab2.setIndicator(this.getResources().getString(R.string.tab2)); tab2.setContent(new Intent().setClass(this, Tab2Activity.class)); tabhost.addTab(tab2); //Tab3設定 TabSpec tab3 = tabhost.newTabSpec(TAB[2]); tab3.setIndicator(this.getResources().getString(R.string.tab3)); tab3.setContent(new Intent().setClass(this, Tab3Activity.class)); tabhost.addTab(tab3); //初期表示するタブ tabhost.setCurrentTab(0); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }この方法はアクティビティがいっぱいになるのがイヤだな・・・
layoutファイルに定義したViewを表示する
最後にTabをクリックした時に表示するコンテンツに、res/layoutに作成したファイルを表示する方法です。 これが一番よいのではと思っています。 res/layoutを右クリックし「新規」→「その他」→「Android XML レイアウト・ファイル」を選択し 「tab1.xml」、「tab2.xml」、「tab3.xml」を作成します。 ルート要素はLinearLayoutにし、それぞれの違いがわかるように適当にウィジェットを配置しておきます。 次にメインとなるActivityを作成します。 こちらは「TabHostを配置したアクティビティに定義したViewを表示する」で作成したMainActivity.javaとほぼ同じです。 違いは、TabSpec#setContent()でTabContentFactoryインターフェースを実装したクラスを指定します。 TabContentFactoryのcreateTabContent()メソッドで先ほど作成したレイアウトファイルを返すようにします。 MainActivity.javapublic class MainActivity extends TabActivity { private static final String TAB[] = {"tab1", "tab2","tab3" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //タブに表示するViewをlayoutより取得する LayoutInflater layout = LayoutInflater.from(MainActivity.this); final View viewTab1 = layout.inflate(R.layout.tab1, null); final View viewTab2 = layout.inflate(R.layout.tab2, null); final View viewTab3 = layout.inflate(R.layout.tab3, null); //TabHostオブジェクト取得 TabHost tabhost = getTabHost(); //Tab1設定 TabSpec tab1 = tabhost.newTabSpec(TAB[0]); tab1.setIndicator(this.getResources().getString(R.string.tab1)); tab1.setContent(new TabHost.TabContentFactory (){ public View createTabContent(String tag) {return viewTab1;} }); tabhost.addTab(tab1); //Tab2設定 TabSpec tab2 = tabhost.newTabSpec(TAB[1]); tab2.setIndicator(this.getResources().getString(R.string.tab2)); tab2.setContent(new TabHost.TabContentFactory (){ public View createTabContent(String tag) {return viewTab2;} }); tabhost.addTab(tab2); //Tab3設定 TabSpec tab3 = tabhost.newTabSpec(TAB[2]); tab3.setIndicator(this.getResources().getString(R.string.tab3)); tab3.setContent(new TabHost.TabContentFactory (){ public View createTabContent(String tag) {return viewTab3;} }); tabhost.addTab(tab3); //初期表示するタブ tabhost.setCurrentTab(0); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }今回はちゃんとまとめられたと思うっ( *`ω´)
Android AlertDialogに画像を表示する
以前のAndroid AlertDialogを表示する の「独自のレイアウトを表示する」方法を利用してAlertDialogに画像を表示します。
画像の用意
まずAlertDialogに配置する画像を用意します。 画像はファイルエクスプローラーから\res\drawableフォルダに直接配置します。 drawableフォルダがなければ作成してください。 Androidは .png ( 推奨 )、.jpg ( 容認 )、.gif ( 非推奨 ) の 3つのフォーマットのビットマップをサポートします。 Eclipseが画像を自動で認識して、プロジェクトエクスプローラのres/drawableにそれぞれの画像が表示されます。 画像が読み込まれない場合、メニュー「プロジェクト」→「クリーン」を行ってください。リソースファイルの用意
AlertDialogのメッセージの文字色を白色にしたいので、色リソースを定義します。 Eclipseのプロジェクトエクスプローラのres/valuesを右クリックし「新規」→「その他」→「Android XML 値ファイル」を選択します。 ファイル名を「color」としルート要素に「resources」を選択します。 白色を定義します。 res/values/color.xml<?xml version="1.0" encoding="utf-8"?> <resources> <color name="white">#FFFFFF</color> </resources>
レイアウトファイルの用意
Eclipseのプロジェクトエクスプローラのres/layoutを右クリックし「新規」→「その他」→「Android XML レイアウト・ファイル」を選択します。 ファイル名を「alert」としルート要素に「LinearLayout」を選択しました。 レイアウトファイルには 画像を表示するためのImageViewとメッセージを表示するためのTextViewを配置します。 TextViewのTextColorは先ほど作成した色リソースの白を指定します。 色リソースがEclipseに認識されない場合はプロジェクトのクリーンを行ってください。 res/layout/alert.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@+id/imageAlertIcon" android:layout_width="60dp" android:layout_height="60dp" /> <TextView android:id="@+id/lblMessage" android:layout_width="258dp" android:layout_height="match_parent" android:text="TextView" android:textColor="@color/white" /> </LinearLayout>
AlertDialogを表示するクラスの用意
AlertDialogを表示するクラスAlertHelperクラスを作成します。(ここら辺はおこのみで) レイアウトファイルの用意で作成したalertレイアウトを取得し ImageViewに画像を、TextViewにメッセージを表示します。public class AlertHelper { /** * 警告メッセージを表示します。 * @param context * @param message * @param listenerOK */ public static void showWarning(Context context,String message,DialogInterface.OnClickListener listenerOK){ LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.alert,null); ImageView imgAlertIcon = (ImageView)view.findViewById(R.id.imageAlertIcon); imgAlertIcon.setImageResource(R.drawable.warning); TextView lblMessage = (TextView)view.findViewById(R.id.lblMessage); lblMessage.setText(message); AlertDialog.Builder alert = new AlertDialog.Builder(context); alert.setPositiveButton("OK",listenerOK); alert.setView(view); alert.show(); } /** * エラーメッセージを表示します。 * @param context * @param message * @param listenerOK */ public static void showError(Context context,String message,DialogInterface.OnClickListener listenerOK){ LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.alert,null); ImageView imgAlertIcon = (ImageView)view.findViewById(R.id.imageAlertIcon); imgAlertIcon.setImageResource(R.drawable.error); TextView lblMessage = (TextView)view.findViewById(R.id.lblMessage); lblMessage.setText(message); AlertDialog.Builder alert = new AlertDialog.Builder(context); alert.setPositiveButton("OK",listenerOK); alert.setView(view); alert.show(); } /** * 情報メッセージを表示します。 * @param context * @param message * @param listenerOK */ public static void showInformation(Context context,String message,DialogInterface.OnClickListener listenerOK){ LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.alert,null); ImageView imgAlertIcon = (ImageView)view.findViewById(R.id.imageAlertIcon); imgAlertIcon.setImageResource(R.drawable.information); TextView lblMessage = (TextView)view.findViewById(R.id.lblMessage); lblMessage.setText(message); AlertDialog.Builder alert = new AlertDialog.Builder(context); alert.setPositiveButton("OK",listenerOK); alert.setView(view); alert.show(); } /** * 質問メッセージを表示します。 * @param context * @param message * @param listenerOK */ public static void showQuestion(Context context,String message,DialogInterface.OnClickListener listenerYes,DialogInterface.OnClickListener listenerNo){ LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.alert,null); ImageView imgAlertIcon = (ImageView)view.findViewById(R.id.imageAlertIcon); imgAlertIcon.setImageResource(R.drawable.question); TextView lblMessage = (TextView)view.findViewById(R.id.lblMessage); lblMessage.setText(message); AlertDialog.Builder alert = new AlertDialog.Builder(context); alert.setPositiveButton("YES",listenerYes); alert.setNegativeButton("NO", listenerNo); alert.setView(view); alert.show(); } }質問メッセージを表示してみます。
public class MainActivity extends Activity { public void button1Click(View view) { OnClickListener listenerYes = new OnClickListener(){ public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "Yes", Toast.LENGTH_LONG).show(); } }; AlertHelper.showQuestion(this, "質問メッセージです。", listenerYes , null); } }
Android SDカードに配置したデータベースにアクセスする
SDカードに配置したデータベースにアクセスするには
マニフェストファイルにSD カードのコンテンツの変更/削除の権限を与える設定を行います。
SQLiteOpenHelperを継承したクラスのデータベース名にSDカードのデータベースパスを指定します。
マニフェストファイルにSD カードのコンテンツの変更/削除の権限を与える設定を行います。
SQLiteOpenHelperを継承したクラスのデータベース名にSDカードのデータベースパスを指定します。
public class DatabaseHelperTest extends SQLiteOpenHelper { /* データベース名 */ //private final static String DB_NAME = "HelloAndroid.db"; private final static String DB_NAME = Environment.getExternalStorageDirectory() + "/HelloAndroid.db"; /* データベースのバージョン */ private final static int DB_VER = 1; /* * コンストラクタ */ public DatabaseHelperTest(Context context) { super(context, DB_NAME, null, DB_VER); } @Override public void onCreate(SQLiteDatabase db) { // TODO 自動生成されたメソッド・スタブ } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO 自動生成されたメソッド・スタブ } }あとは従来通りにsqlを発行すればOKです。
Android SDカードに配置したデータベースをデータベースフォルダにコピーする
SDカードに配置したSQLiteデータベースをデータベースフォルダにコピーします。
public class MainActivity extends Activity { public void button1Click(View view){ try { final String DB_NAME = "HelloAndroid.db"; //既存データベースを削除 this.deleteDatabase(DB_NAME); //コピー元パス(SDカード) String pathFrom = Environment.getExternalStorageDirectory().getPath() + "/" + DB_NAME; //コピー先パス(データベースフォルダ) String pathTo = this.getDatabasePath(DB_NAME).getPath(); //コピー FileInputStream fis = new FileInputStream(pathFrom); FileChannel channelFrom = fis.getChannel(); FileOutputStream fos = new FileOutputStream(pathTo); FileChannel channeTo = fos.getChannel(); try { channelFrom.transferTo(0, channelFrom.size(), channeTo); } finally { fis.close(); channelFrom.close(); fos.close(); channeTo.close(); } } catch (Exception e) { e.printStackTrace(); } } }DatabaseHelperのonCreateでやれば良いと思う。
Android SDカードのファイルを読み書きする
実機で実行している場合、「マウント」をOFFします。
(SDカードに書き込みできず、マウントOFFに気づくのに小一時間゜・(ノД`)・゜・)
マニフェストファイルにSD カードのコンテンツの変更/削除の権限を与える設定を行います。
※SDカードから読み込むだけなら必要ありません。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>SDカードは端末によりパスが異なるのでgetExternalStorageDirectory()メソッドでパスを取得します。
String sdPath = Environment.getExternalStorageDirectory().getPath();あとは普通のファイル入出力と同じです。 SDカードに書き込み
public void button1Click(View view) { try { //SDカードフォルダのパス String sdPath = Environment.getExternalStorageDirectory().getPath(); //作成するファイル名 String fileName = "/Hello.txt"; //書き込み BufferedWriter bw = null; try { FileWriter fw = new FileWriter(sdPath + fileName); bw = new BufferedWriter(fw); bw.write("ハロー"); } finally { bw.close(); } } catch (Exception e) { e.printStackTrace(); } }SDカードに書き込み
public void button2Click(View view) { try { //SDカードフォルダのパス String sdPath = Environment.getExternalStorageDirectory().getPath(); //読み込むァイル名 String fileName = "/Hello.txt"; //読み込み BufferedReader br = null; try { FileReader fr = new FileReader(sdPath + fileName); br = new BufferedReader(fr); StringBuilder sb = new StringBuilder(); String str; while((str = br.readLine()) != null){ sb.append(str +"\r\n"); } Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show(); } finally { br.close(); } }catch (Exception e){ e.printStackTrace(); } }
.NET OracleデータベースのデータをSQLiteデータベースに移送する
前回、VisualStudioでSQLiteを使用できるようにしました。
.NET VisualStudioでSQLiteを使用する
今回は既存のOracleデータベースの選択したテーブルから、SQLiteにテーブルを作成しデータを移送するコードです。
データ移送がメンドイので作りました。自分用のメモです。
画面を表示するとリストボックスにOracleデータベースのテーブル一覧が表示されます。
SQLiteDB選択ボタンでデータを移送するSQLiteデータベースを選択してください。
データ移送ボタンで処理を実行します。
.NET VisualStudioでSQLiteを使用する
今回は既存のOracleデータベースの選択したテーブルから、SQLiteにテーブルを作成しデータを移送するコードです。
データ移送がメンドイので作りました。自分用のメモです。
画面を表示するとリストボックスにOracleデータベースのテーブル一覧が表示されます。
SQLiteDB選択ボタンでデータを移送するSQLiteデータベースを選択してください。
データ移送ボタンで処理を実行します。
Imports System.Data.Common Public Class FrmOracleToSqlite Private Const CONNECTION_STRING_PC As String = "user id=xxxxx;password=xxxxx;data source=xxxxx" Private Const PROVIDER_NAME_PC As String = "System.Data.OracleClient" Private _ConnectionStringAndroid As String = "data source={0}" Private Const PROVIDER_NAME_ANDROID As String = "System.Data.SQLite" Private Sub Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load SetTableNameList() End Sub Private Sub cmdSelectDb_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdSelectDb.Click Using dialog As New OpenFileDialog If dialog.ShowDialog() = Windows.Forms.DialogResult.OK Then Me._ConnectionStringAndroid = String.Format(Me._ConnectionStringAndroid, dialog.FileName) Me.lblDbNm.Text = Me._ConnectionStringAndroid End If End Using End Sub Private Sub cmdExec_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdExec.Click If Me.lstTableName.CheckedItems.Count = 0 Then MessageBox.Show("テーブルを選択して下さい。") Return End If System.Windows.Forms.Cursor.Current = Cursors.WaitCursor For Each sTableName As String In Me.lstTableName.CheckedItems CreateTableForAndroid(sTableName) Next MessageBox.Show("終了~!") End Sub '-----Private----- Private Sub SetTableNameList() Dim factory As DbProviderFactory = DbProviderFactories.GetFactory(PROVIDER_NAME_PC) Dim tbl As New DataTable Using cnn As DbConnection = factory.CreateConnection() cnn.ConnectionString = CONNECTION_STRING_PC cnn.Open() Try Using cmd As DbCommand = cnn.CreateCommand cmd.CommandText = "select table_name from user_tables order by table_name" Using adp As DbDataAdapter = factory.CreateDataAdapter adp.SelectCommand = cmd adp.Fill(tbl) End Using End Using Finally cnn.Close() End Try End Using 'cnn For idx As Integer = 0 To tbl.Rows.Count - 1 Me.lstTableName.Items.Add(tbl.Rows(idx).Item(0).ToString, False) Next End Sub Private Sub CreateTableForAndroid(ByVal sTableName As String) Dim factoryPC As DbProviderFactory = DbProviderFactories.GetFactory(PROVIDER_NAME_PC) Dim factoryAD As DbProviderFactory = DbProviderFactories.GetFactory(PROVIDER_NAME_ANDROID) 'PC側テーブル情報を取得 Dim tblSchema As New DataTable Dim tblPKey As New DataTable Using cnn As DbConnection = factoryPC.CreateConnection() cnn.ConnectionString = CONNECTION_STRING_PC cnn.Open() Try Using adp As DbDataAdapter = factoryPC.CreateDataAdapter '--列情報 Using cmd As DbCommand = cnn.CreateCommand adp.SelectCommand = cmd Dim sbSql As New System.Text.StringBuilder With sbSql .AppendLine("select") .AppendLine(" C.Column_Name") .AppendLine(" ,C.Data_type") .AppendLine(" ,C.Data_precision") .AppendLine(" ,C.Data_scale") .AppendLine(" ,C.Nullable") .AppendLine("FROM USER_TAB_COLUMNS C") .AppendLine(" INNER JOIN USER_TABLES T ON") .AppendLine(" C.Table_Name = T.Table_Name") .AppendLine("WHERE") .AppendLine(" T.Table_Name='" & sTableName & "'") End With cmd.CommandText = sbSql.ToString adp.Fill(tblSchema) End Using '--主キー情報 Using cmd As DbCommand = cnn.CreateCommand adp.SelectCommand = cmd Dim sbSql As New System.Text.StringBuilder With sbSql .AppendLine("SELECT") .AppendLine(" B.COLUMN_NAME AS COL_NAME") .AppendLine("FROM USER_CONSTRAINTS A") .AppendLine(" LEFT JOIN USER_CONS_COLUMNS B ON") .AppendLine(" B.TABLE_NAME = A.TABLE_NAME") .AppendLine(" AND B.CONSTRAINT_NAME = A.CONSTRAINT_NAME") .AppendLine("WHERE") .AppendLine(" B.TABLE_NAME = '" & sTableName & "'") .AppendLine(" AND A.CONSTRAINT_TYPE = 'P'") End With cmd.CommandText = sbSql.ToString adp.Fill(tblPKey) End Using End Using Finally cnn.Close() End Try End Using 'cnn 'Android側にテーブル作成 '--Drop文作成 Dim sSqlDrop As String = "DROP TABLE " & sTableName '--主キーリスト作成 Dim lstPKey As New List(Of String) For Each r As DataRow In tblPKey.Rows lstPKey.Add(r.Item("COL_NAME").ToString) Next '--Create文作成 Dim sqlCreate As New System.Text.StringBuilder With sqlCreate .AppendLine("CREATE TABLE " & sTableName & "(") For idx As Integer = 0 To tblSchema.Rows.Count - 1 If idx <> 0 Then .Append(",") End If .Append(tblSchema.Rows(idx).Item("Column_Name").ToString) Select Case tblSchema.Rows(idx).Item("Data_type").ToString Case "VARCHAR2", "DATE" .Append(" TEXT") Case "NUMBER" If CInt(tblSchema.Rows(idx).Item("data_scale")) = 0 Then .Append(" NUMBER") Else .Append(" REAL") End If End Select If tblSchema.Rows(idx).Item("Nullable").ToString = "N" Then .Append(" NOT NULL") End If .AppendLine("") Next sqlCreate.AppendLine(",PRIMARY KEY (" & String.Join(",", lstPKey.ToArray) & ")") sqlCreate.AppendLine(")") End With '--テーブル作成 Using cnn As DbConnection = factoryAD.CreateConnection() cnn.ConnectionString = Me._ConnectionStringAndroid cnn.Open() Try Using adp As DbDataAdapter = factoryAD.CreateDataAdapter Using cmd As DbCommand = cnn.CreateCommand cmd.CommandText = sSqlDrop Try cmd.ExecuteNonQuery() Catch ex As Exception '何もしない End Try cmd.CommandText = sqlCreate.ToString cmd.ExecuteNonQuery() End Using End Using Finally cnn.Close() End Try End Using 'cnn 'データ移送 Const DATA_CNT As Integer = 100 Dim iSt As Integer = 0 Dim iEd As Integer = iSt + DATA_CNT - 1 '--PC側データのSELECT文の作成 Dim sqlSelect As New System.Text.StringBuilder With sqlSelect .AppendLine("SELECT TMPTABLE2.* FROM") .AppendLine(String.Format("(SELECT ROWNUM AS ROW_NUM, {0}.* FROM {0} ) TMPTABLE2", sTableName)) .AppendLine("WHERE ROW_NUM >= :ROW_NUM_Sta") .AppendLine("AND ROW_NUM <= :ROW_NUM_End") End With Dim cmdSelect As DbCommand = factoryPC.CreateCommand cmdSelect.CommandText = sqlSelect.ToString Dim pSt As DbParameter = factoryPC.CreateParameter pSt.ParameterName = "ROW_NUM_Sta" cmdSelect.Parameters.Add(pSt) Dim pEd As DbParameter = factoryPC.CreateParameter pEd.ParameterName = "ROW_NUM_End" cmdSelect.Parameters.Add(pEd) '--Android側のInsert文の作成 Dim lstColNm As New List(Of String) Dim lstPrmmNm As New List(Of String) For Each row As DataRow In tblSchema.Rows lstColNm.Add(row.Item("Column_Name").ToString) lstPrmmNm.Add("@" & row.Item("Column_Name").ToString) Next Dim sqlInsert As New System.Text.StringBuilder With sqlInsert .AppendLine("INSERT INTO " & sTableName & "(") .AppendLine(String.Join(","c, lstColNm.ToArray)) .AppendLine(")VALUES(") .AppendLine(String.Join(","c, lstPrmmNm.ToArray)) .AppendLine(")") End With Dim cmdInsert As DbCommand = factoryAD.CreateCommand cmdInsert.CommandText = sqlInsert.ToString For Each colnm As String In lstColNm Dim prm As DbParameter = factoryAD.CreateParameter prm.ParameterName = colnm prm.SourceColumn = colnm prm.SourceVersion = DataRowVersion.Current cmdInsert.Parameters.Add(prm) Next '--データをSelectしInsertをDATA_CNT件づつ繰り返す Using cnnPC As DbConnection = factoryPC.CreateConnection() cnnPC.ConnectionString = CONNECTION_STRING_PC cnnPC.Open() Try Using cnnAd As DbConnection = factoryAD.CreateConnection() cnnAd.ConnectionString = Me._ConnectionStringAndroid cnnAd.Open() Try cmdSelect.Connection = cnnPC cmdInsert.Connection = cnnAd Do '----Select実行 Dim tblSelect As New DataTable Using adp As DbDataAdapter = factoryPC.CreateDataAdapter adp.SelectCommand = cmdSelect cmdSelect.Parameters(pSt.ParameterName).Value = iSt cmdSelect.Parameters(pEd.ParameterName).Value = iEd adp.Fill(tblSelect) End Using If tblSelect.Rows.Count = 0 Then Exit Do End If '----取得したデータの行状態を追加にする For Each row As DataRow In tblSelect.Rows row.SetAdded() Next '----Insert実行 Using adp As DbDataAdapter = factoryAD.CreateDataAdapter adp.InsertCommand = cmdInsert adp.Update(tblSelect) End Using '----インクリメント iSt = iEd + 1 iEd = iSt + DATA_CNT - 1 Loop Finally cnnAd.Close() End Try End Using 'cnnAd Finally cnnPC.Close() End Try End Using 'cnnPC End Sub End Class
.NET VisualStudioでSQLiteを使用する
Androidで使用するSQLiteデータベースをPC側で作成したいと思います。
少量のデータでしたらAndroid SQLiteのGUIツールで紹介したツールを使えば作成できます。
今回はVisualStudioでSQLiteを使えるようにしたいと思います。
http://sqlite.phxsoftware.com/
SQLite-1.0.66.0-managedonly-binaries.zip:クラスライブラリのみ
SQLitem-1.0.66.0-setup.exe:setupファイル。IDEへの登録も行う。サーバーエクスプローラなどから使用したければこちらを選択
ダウンロードしたSQLitem-1.0.66.0-setup.exeをインストールします。
VisualStudioを起動し、プロジェクトを作成します。
サーバーエクスプローラより「データ接続」を右クリックし「接続の追加」を選択。
開いたダイアログのデータソースをSQLiteに変更します。
「NEW...」ボタンで新しいデータベースを作成します。
プログラムからデータベースへアクセスする方法も従来と同じです。
参照設定に「System.Data.SQLite」を追加します。
少量のデータでしたらAndroid SQLiteのGUIツールで紹介したツールを使えば作成できます。
今回はVisualStudioでSQLiteを使えるようにしたいと思います。
ADO.NET 2.0 Provider for SQLiteをインストール
以下のサイトよりSQLitem-1.0.66.0-setup.exeをダウンロードします。http://sqlite.phxsoftware.com/
SQLite-1.0.66.0-managedonly-binaries.zip:クラスライブラリのみ
SQLitem-1.0.66.0-setup.exe:setupファイル。IDEへの登録も行う。サーバーエクスプローラなどから使用したければこちらを選択
ダウンロードしたSQLitem-1.0.66.0-setup.exeをインストールします。
VisualStudioからSQLiteを使用する
VisualStudio2008での解説です。VisualStudioを起動し、プロジェクトを作成します。
サーバーエクスプローラより「データ接続」を右クリックし「接続の追加」を選択。
開いたダイアログのデータソースをSQLiteに変更します。
「NEW...」ボタンで新しいデータベースを作成します。
プログラムからデータベースへアクセスする方法も従来と同じです。
参照設定に「System.Data.SQLite」を追加します。
Private Sub AccessSQLite() Const CONNECTION_STRING As String = "data source=C:\Android\Database\HelloAndroid" Const PROVIDER_NAME As String = "System.Data.SQLite" Dim factory As DbProviderFactory = DbProviderFactories.GetFactory(PROVIDER_NAME) Using cnn As DbConnection = factory.CreateConnection() cnn.ConnectionString = CONNECTION_STRING cnn.Open() Try Using cmd As DbCommand = factory.CreateCommand cmd.Connection = cnn cmd.CommandText = "CREATE TABLE 省略" cmd.ExecuteNonQuery() End Using Finally cnn.Close() End Try End Using End Sub
Android 実機で実行(Softbank Sharp 003SH)
作ったアプリを実機でデバッグ実行しようと思います。
まずはAndroid端末とPCの接続からです。
ここで私の持っているAndroid端末Softbank Sharp 003SHとWindowsVistaでの手順を紹介します。
端末が古いですが自分用のメモということで。
Android端末とPCをUSB接続できるようにする
003SH用のUSBドライバのインストール 以下のサイトよりファイルをダウンロードしてPCにインストールします。 http://k-tai.sharp.co.jp/support/s/003sh/ SHARP共通 ADB USBドライバのインストール- 以下のサイトよりファイルをダウンロードし解凍します。 https://sh-dev.sharp.co.jp/android/modules/driver/#adbAll
- 端末設定の「USBデバッグ」にチェックを入れ、有効にします。 (設定 > アプリケーション > 開発 > USBデバッグ)
- デバイスとPCをUSBで繋ぐとAndroid Composite ADB Interfaceを認識し、ドライバのインストール画面が起動します。
- ドライバ格納先で"\usb_driver_SHARP"を選択し、ドライバをインストールします。
Android端末のフォルダをPCから見れるようにする
マイコンピュータに表示されているAndroid端末「リムーバルディスク」ですが、クリックしても「ディスクを挿入してください」と 端末の中を見ることができません。 端末の中のフォルダを見るには、USBとPCを繋いだ状態で、画面上部のステータスバーを下にドラッグします。 表示される通知領域から「USB接続」を選択します。 「USBマスストレージ」画面が表示されるので「マウント」ボタンをクリックします。 これでAndroid端末の中のフォルダが参照できるようになります。実機でアプリを実行する
まずAndroid端末の設定>アプリケーション>開発>USBデバッグをONに設定します。 次にEclipseを起動し、プロジェクトエクスプローラから実行するプロジェクトを右クリックで「実行」→「実行の構成」を選択します。 「ターゲット」タブを選択し「デバイスを選択するときに常にプロンプトを表示」をチェックONにし「実行」ボタンでダイアログを閉じます。 プロジェクトエクスプローラより実行するプロジェクトを右クリックで「実行」→「Androidアプリケーション」を選択すると 「Androidデバイスの選択」ダイアログが開くので実行するデバイスを選択し、「OK]ボタンで実行します。 Android端末のUSBデバッグをONに設定していないと、ここで接続している端末を認識しません。 これで実機でデバッグ実行できます。Android AsyncTask#doInBackground内での例外をUIスレッドに通知する
Android AsyncTaskでProgressDialogを表示 その1
Android AsyncTaskでProgressDialogを表示 その2
前回までに作ったProgressBarを表示するAsyncTaskですが
doInBackgroundメソッド内で発生した例外をUIスレッドに通知したいと思います。
バックグラウンドで発生した例外をUIスレッドに通知するにはHandlerクラスを使用します。
詳しい説明や使い方はコチラなどが参考になりました。
愚鈍人 HandlerとMessage - 別スレッドでのGUI操作
ようはUIスレッドでHandlerクラスのインスタンスを生成し、
このインスタンスのsendMessageメソッドでバックグラウンドからUIスレッドに通知できます。
またHandlerクラスのhandleMessageメソッドをオーバライドして、バックグラウンドから通知を受けたときの処理を書きます。
MainActivity.java
ボタンをクリックするとバックグラウンドで処理を実行します。
処理を行うクラス(ReceiveDataクラス)のコンストラクタの引数にHandlerオブジェクトを指定しています。
またHandlerクラスのhandleMessageメソッドをオーバライドして、発生した例外のメッセージを表示します。
※「This Handler class should be static or leaks might occur」と警告が出ますが、今はとりあえず無視します(^^;
ProgressAsyncTask.java
プログレスバーを表示するAsyncTaskクラスです。
ReceiveData.java
実際にバックグラウンドで行う処理です。
ループ変数 i が 7 になったときRuntimeExceptionをスローし、 catch句でHandlerオブジェクトのsendMessageメソッドを実行しています。
実行するとUIスレッドでメッセージが表示されます。
さて次は「This Handler class should be static or leaks might occur」と警告が出ないようMainActivityを修正します。
修正方法はコチラを参考に
http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler
HandlerクラスをStaticクラスにします。
MainActivity
Android AsyncTaskでProgressDialogを表示 その2
前回までに作ったProgressBarを表示するAsyncTaskですが
doInBackgroundメソッド内で発生した例外をUIスレッドに通知したいと思います。
バックグラウンドで発生した例外をUIスレッドに通知するにはHandlerクラスを使用します。
詳しい説明や使い方はコチラなどが参考になりました。
愚鈍人 HandlerとMessage - 別スレッドでのGUI操作
ようはUIスレッドでHandlerクラスのインスタンスを生成し、
このインスタンスのsendMessageメソッドでバックグラウンドからUIスレッドに通知できます。
またHandlerクラスのhandleMessageメソッドをオーバライドして、バックグラウンドから通知を受けたときの処理を書きます。
MainActivity.java
ボタンをクリックするとバックグラウンドで処理を実行します。
処理を行うクラス(ReceiveDataクラス)のコンストラクタの引数にHandlerオブジェクトを指定しています。
またHandlerクラスのhandleMessageメソッドをオーバライドして、発生した例外のメッセージを表示します。
※「This Handler class should be static or leaks might occur」と警告が出ますが、今はとりあえず無視します(^^;
package com.example.helloandroid; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { //Activityが破棄されても、オブジェクトを保持できるようにstaticで宣言する。 private static ProgressAsyncTask<Void,Boolean> mTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //プログレスダイアログを再表示する。 if (mTask != null && mTask.getIsShowProgress()){ mTask.showDialog(); } } @Override protected void onPause() { //プログレスダイアログを閉じる。 if (mTask != null && mTask.getIsShowProgress()) { mTask.dismissDialog(); } super.onPause(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } /** * button1クリック処理 * @param view * バックグラウンドで処理を行う */ public void button1Click(View view){ final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { Throwable e = (Throwable)msg.obj; Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show(); } }; //final MyHandler handler = new MyHandler(this); mTask = new ProgressAsyncTask<Void,Boolean>(this){ @Override protected Boolean doInBackground(Void... params) { ReceiveData receive = new ReceiveData(mTask,handler); Boolean ret = receive.getMethod1(); return ret; }}; mTask.execute(); } }
ProgressAsyncTask.java
プログレスバーを表示するAsyncTaskクラスです。
package com.example.helloandroid; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Bundle; /** * ProgressAsyncTask * プログレスダイアログを表示し、バックグラウンドで処理を行う抽象クラスです。 * @param <Param> * @param <Result> * */ public abstract class ProgressAsyncTask<Param,Result> extends AsyncTask<Param,Bundle,Result>{ private Context mContext; private ProgressDialog mProgressDialog; private Boolean isShowProgress; /** * コンストラクタ * @param context * @param procName */ public ProgressAsyncTask(Context context){ mContext = context; } /** * getIsShowProgress * プログレスダイアログが表示中かどうかを返します。 * @return */ public Boolean getIsShowProgress() { return isShowProgress; } /** * onPreExecute * 最初にUIスレッドで呼び出されます。 * UIに関わる処理をします。 */ @Override protected void onPreExecute() { super.onPreExecute(); showDialog(); isShowProgress = true; } /** * onProgressUpdate * doInBackground内でpublishProgressメソッドが呼ばれると、 UIスレッド上でこのメソッドが呼ばれます。 * このメソッドの引数の型はAsyncTaskの二つ目のパラメータです。 * @param values */ @Override protected void onProgressUpdate(Bundle... values) { super.onProgressUpdate(values); Bundle bundle = values[0]; if (bundle.containsKey("Message")){ mProgressDialog.setMessage(bundle.getString("Message")); } if (bundle.containsKey("Max")){ mProgressDialog.setMax(bundle.getInt("Max")); } if (bundle.containsKey("Progress")){ mProgressDialog.setProgress(bundle.getInt("Progress")); } } /** * onPostExecute * doInBackground が終わるとそのメソッドの戻り値をパラメータとして渡して onPostExecute が呼ばれます。 * このパラメータの型は AsyncTask を extends するときの三つめのパラメータです。 * バックグラウンド処理が終了し、メインスレッドに反映させる処理をここに書きます。 * @param result */ @Override protected void onPostExecute(Result result) { super.onPostExecute(result); dismissDialog(); isShowProgress = false; } /** * onCancelled * cancelメソッドが呼ばれるとonCancelledメソッドが呼ばれます。 */ @Override protected void onCancelled() { super.onCancelled(); dismissDialog(); isShowProgress = false; } /** * showDialog * プログレスダイアログを表示します。 */ public void showDialog() { mProgressDialog = new ProgressDialog(mContext); mProgressDialog.setMessage(""); //途中でメッセージを変更するために必要 mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setIndeterminate(false); mProgressDialog.setCancelable(true); mProgressDialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cancel(true); // 非同期処理をキャンセルする } }); mProgressDialog.show(); } /** * dismissDialog * ダイアログを終了します。 */ public void dismissDialog() { mProgressDialog.dismiss(); mProgressDialog = null; } /** * setProgressMessage * プログレスダイアログのメッセージを設定します。 * @param message */ public void setProgressMessage(String message){ Bundle data = new Bundle(); data.putString("Message", message); publishProgress(data); } /** * setMax * プログレスダイアログの最大値を設定します。 * @param max */ public void setProgressMax(int max){ Bundle data = new Bundle(); data.putInt("Max", max); publishProgress(data); } /** * setProgress * プログレスダイアログの進捗値を設定します。 * @param max */ public void setProgress(int progress){ Bundle data = new Bundle(); data.putInt("Progress", progress); publishProgress(data); } }
ReceiveData.java
実際にバックグラウンドで行う処理です。
ループ変数 i が 7 になったときRuntimeExceptionをスローし、 catch句でHandlerオブジェクトのsendMessageメソッドを実行しています。
package com.example.helloandroid; import android.os.Handler; import android.os.Message; import android.os.SystemClock; public class ReceiveData { private ProgressAsyncTask<?,?> mTask; private Handler mHandler; /** * コンストラクタ * @param task * @param handler */ public ReceiveData(ProgressAsyncTask<?,?> task, Handler handler){ mTask = task; mHandler = handler; } /** * getMethod1 */ public Boolean getMethod1(){ try { mTask.setProgressMessage("Method1_Start"); mTask.setProgressMax(10); for(int i=0; i<10; i++){ mTask.setProgress(i+1); SystemClock.sleep(1000); if (i == 7) { throw new RuntimeException("エラー! i==7です。"); } if (mTask.isCancelled()) { return false; } } return true; } catch (Exception e) { e.printStackTrace(); final Message msg = new Message(); msg.obj = e; new Thread(new Runnable(){ public void run() { mHandler.sendMessage(msg); }}).start(); mTask.cancel(true); return false; } } }
実行するとUIスレッドでメッセージが表示されます。
さて次は「This Handler class should be static or leaks might occur」と警告が出ないようMainActivityを修正します。
修正方法はコチラを参考に
http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler
HandlerクラスをStaticクラスにします。
MainActivity
package com.example.helloandroid; import java.lang.ref.WeakReference; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { //Activityが破棄されても、オブジェクトを保持できるようにstaticで宣言する。 private static ProgressAsyncTask<Void,Boolean> mTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //プログレスダイアログを再表示する。 if (mTask != null && mTask.getIsShowProgress()){ mTask.showDialog(); } } @Override protected void onPause() { //プログレスダイアログを閉じる。 if (mTask != null && mTask.getIsShowProgress()) { mTask.dismissDialog(); } super.onPause(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } /** * button1クリック処理 * @param view * バックグラウンドで処理を行う */ public void button1Click(View view){ final MyHandler handler = new MyHandler(this); mTask = new ProgressAsyncTask<Void,Boolean>(this){ @Override protected Boolean doInBackground(Void... params) { ReceiveData receive = new ReceiveData(mTask,handler); Boolean ret = receive.getMethod1(); return ret; }}; mTask.execute(); } /** * MyHandlerクラス * バックグラウンドで例外発生時の処理 */ private static class MyHandler extends Handler { private final WeakReference<MainActivity> mActivity; public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { MainActivity activity = mActivity.get(); if (activity == null){ return; } Throwable e = (Throwable)msg.obj; Toast.makeText(mActivity.get(), e.getMessage(), Toast.LENGTH_LONG).show(); } } }
Android JSONObjectのNull判定
ちょっぴりハマったのでメモです。
JSONObjectのNull判定は以下のようにします。
しらずに「jsonObject.get(name) == null」って書いて小一時間ムダにした(;´Д`A
JSONObjectのNull判定は以下のようにします。
if (jsonObject.get(name) == JSONObject.NULL){ //JsonObjectはnull }
しらずに「jsonObject.get(name) == null」って書いて小一時間ムダにした(;´Д`A
Android AsyncTaskでProgressDialogを表示 その2
Android AsyncTaskでProgressDialogを表示 その1
進捗を表示しながらバックグラウンドで処理を行うことってよくあるのですが、 まいどまいどAsyncTaskを作っていられないので自分なりの進捗を表示するAsyncTaskを作ってみました。
自分用のメモです。
ProgressAsyncTask
Activity
ボタンをクリックするとバックグラウンドでgetMethod1()とgetMethod2()を実行します。
getMethod1()とgetMethod2()メソッドを定義しているクラスです。
進捗を表示しながらバックグラウンドで処理を行うことってよくあるのですが、 まいどまいどAsyncTaskを作っていられないので自分なりの進捗を表示するAsyncTaskを作ってみました。
自分用のメモです。
ProgressAsyncTask
package com.example.helloandroid.tool; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Bundle; /** * ProgressAsyncTask * プログレスダイアログを表示し、バックグラウンドで処理を行う抽象クラスです。 * @param <Param> * @param <Result> * */ public abstract class ProgressAsyncTask<Param,Result> extends AsyncTask<Param,Bundle,Result>{ private Context mContext; private ProgressDialog mProgressDialog; private Boolean isShowProgress; /** * コンストラクタ * @param context * @param procName */ public ProgressAsyncTask(Context context){ mContext = context; } /** * getIsShowProgress * プログレスダイアログが表示中かどうかを返します。 * @return */ public Boolean getIsShowProgress() { return isShowProgress; } /** * onPreExecute * 最初にUIスレッドで呼び出されます。 * UIに関わる処理をします。 */ @Override protected void onPreExecute() { super.onPreExecute(); showDialog(); isShowProgress = true; } /** * onProgressUpdate * doInBackground内でpublishProgressメソッドが呼ばれると、 UIスレッド上でこのメソッドが呼ばれます。 * このメソッドの引数の型はAsyncTaskの二つ目のパラメータです。 * @param values */ @Override protected void onProgressUpdate(Bundle... values) { super.onProgressUpdate(values); Bundle bundle = values[0]; if (bundle.containsKey("Message")){ mProgressDialog.setMessage(bundle.getString("Message")); } if (bundle.containsKey("Max")){ mProgressDialog.setMax(bundle.getInt("Max")); } if (bundle.containsKey("Progress")){ mProgressDialog.setProgress(bundle.getInt("Progress")); } } /** * onPostExecute * doInBackground が終わるとそのメソッドの戻り値をパラメータとして渡して onPostExecute が呼ばれます。 * このパラメータの型は AsyncTask を extends するときの三つめのパラメータです。 * バックグラウンド処理が終了し、メインスレッドに反映させる処理をここに書きます。 * @param result */ @Override protected void onPostExecute(Result result) { super.onPostExecute(result); dismissDialog(); isShowProgress = false; } /** * onCancelled * cancelメソッドが呼ばれるとonCancelledメソッドが呼ばれます。 */ @Override protected void onCancelled() { super.onCancelled(); dismissDialog(); isShowProgress = false; } /** * showDialog * プログレスダイアログを表示します。 */ public void showDialog() { mProgressDialog = new ProgressDialog(mContext); mProgressDialog.setMessage(""); //途中でメッセージを変更するために必要 mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setIndeterminate(false); mProgressDialog.setCancelable(true); mProgressDialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cancel(true); // 非同期処理をキャンセルする } }); mProgressDialog.show(); } /** * dismissDialog * ダイアログを終了します。 */ public void dismissDialog() { mProgressDialog.dismiss(); mProgressDialog = null; } /** * setProgressMessage * プログレスダイアログのメッセージを設定します。 * @param message */ public void setProgressMessage(String message){ Bundle data = new Bundle(); data.putString("Message", message); publishProgress(data); } /** * setMax * プログレスダイアログの最大値を設定します。 * @param max */ public void setProgressMax(int max){ Bundle data = new Bundle(); data.putInt("Max", max); publishProgress(data); } /** * setProgress * プログレスダイアログの進捗値を設定します。 * @param max */ public void setProgress(int progress){ Bundle data = new Bundle(); data.putInt("Progress", progress); publishProgress(data); } }
Activity
ボタンをクリックするとバックグラウンドでgetMethod1()とgetMethod2()を実行します。
import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.Toast; import com.example.helloandroid.R; import com.example.helloandroid.service.ReceiveData; import com.example.helloandroid.tool.DatabaseHelper; import com.example.helloandroid.tool.ProgressAsyncTask; public class MainActivity extends Activity { //Activityが破棄されても、オブジェクトを保持できるようにstaticで宣言する。 private static ProgressAsyncTask<?,?> mTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //プログレスダイアログを再表示する。 if (mTask != null && mTask.getIsShowProgress()){ mTask.showDialog(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onPause() { //プログレスダイアログを閉じる。 if (mTask != null && mTask.getIsShowProgress()) { mTask.dismissDialog(); } super.onPause(); } /** * button1Click * @param view * button1クリック時の処理 * */ public void button2Click(View view) { ProgressAsyncTask<Void,Boolean> task = new ProgressAsyncTask<Void,Boolean>(this){ @Override protected Boolean doInBackground(Void... params) { ReceiveData receive = new ReceiveData(MainActivity.this); if (receive.getMethod1(this) == false ){ return false; } if (receive.getMethod2(this) == false) { return false; } return true; }}; mTask = task; task.execute(); } }
getMethod1()とgetMethod2()メソッドを定義しているクラスです。
package com.example.helloandroid.service; import com.example.helloandroid.tool.ProgressAsyncTask; import android.os.SystemClock; public class ReceiveData { /** * getMethod1 * @param task */ public Boolean getMethod1(ProgressAsyncTask<?,?> task){ task.setProgressMessage("Method1_Start"); task.setProgressMax(10); for(int i=0; i<10; i++){ task.setProgress(i+1); SystemClock.sleep(1000); if (task.isCancelled()) { return false; } } return true; } /** * getMethod2 * @param task */ public Boolean getMethod2(ProgressAsyncTask<?,?> task){ task.setProgressMessage("Method2_Start"); task.setProgressMax(20); for(int i=0; i<20; i++){ task.setProgress(i+1); SystemClock.sleep(1000); if (task.isCancelled()) { return false; } } return true; } }
Android AsyncTaskでProgressDialogを表示 その1
AsyncTaskは別スレッドでのバックグラウンド処理とバックグラウンド前後にUIスレッドの操作を行う抽象クラスです。
AsyncTaskを継承するとき実行時引数(Param)、進捗単位(Progress)、処理結果(Result)で扱う[型]を指定します。
実行時引数(Param)はdoInBackgroundメソッドの引数の型になり、
処理結果(Result)はdoInBackgroundメソッドの戻り値の型になります。
進捗単位(Progress)はonProgressUpdateメソッドの引数の型になります。
また、doInBackgroundメソッドの戻り値を引数にonPostExecuteメソッドが呼ばれるので、このメソッドの引数の型は処理結果(Result)の型と同じになります。
AsyncTaskには以下のメソッドがあります。
AsyncTaskでProgressDialogを表示する際のキモは、以下の2点です。
AsyncTaskを継承したProgressTaskクラス
これはディスプレイの縦横を変更すると呼び出し元のアクティビティが破棄され、新しい向きのActivityが生成されます。 そのためダイアログも消えてしまうようです。
またAsyncTaskの処理が終了した時点でIllegalArgumentExceptionが発生してしまいます。
これはダイアログのdismissメソッドを呼び出す時に、ダイアログを表示したアクティビティが破棄されているのが原因のようです。
詳しくはこちらに書かれています。
Tech Racho「Android: ダイアログを表示して縦横が変わるとdismissでエラー」
kasa0の部屋「ProgressDialogとAsyncTaskの甘い罠」
対策は
ProgressTaskクラスでダイアログ表示中かどうかの状態を管理します。
MainActivityクラスでProgressTaskオブジェクトをstatic変数で保持します。
MainActivityクラスのonPauseメソッドでプログレスダイアログを閉じます。
MainActivityクラスのonCreateメソッドでプログレスダイアログを表示します。
キャンセル時の処理について
キャンセルボタンクリック時にProgressTask#cancel(true)を呼びます。
doInBackgroundメソッドではキャンセルされたかどうかを見て、処理を行います。
キャンセルされるとonPostExecute()メソッドは呼ばれない為、onCancelledメソッドで終了処理を行います。
AsyncTaskを継承するとき実行時引数(Param)、進捗単位(Progress)、処理結果(Result)で扱う[型]を指定します。
実行時引数(Param)はdoInBackgroundメソッドの引数の型になり、
処理結果(Result)はdoInBackgroundメソッドの戻り値の型になります。
進捗単位(Progress)はonProgressUpdateメソッドの引数の型になります。
また、doInBackgroundメソッドの戻り値を引数にonPostExecuteメソッドが呼ばれるので、このメソッドの引数の型は処理結果(Result)の型と同じになります。
public class ProgressTask extends AsyncTask<String, Integer, Boolean>{ protected Boolean doInBackground(String... params) {} protected void onPostExecute(Boolean result) { protected void onProgressUpdate(Integer... values) {} }型を何も指定しない場合は「Void」を指定します。
public class ProgressTask extends AsyncTask<Void, Void, Void>{ protected Void doInBackground(Void... params) {} protected void onProgressUpdate(Void... values) {} protected void onPostExecute(Void result){} }
AsyncTaskには以下のメソッドがあります。
- onPreExecute()・・・最初にUIスレッドで呼び出されます。UIに関わる処理をします。
- doInBackground()・・・ワーカースレッド上で実行されます。ここでバックグラウンドで行う時間のかかる処理をします。
- onProgressUpdate()・・・doInBackground内でpublishProgressメソッドが呼ばれると、 UIスレッドでこのメソッドが呼び出されます。
- onPostExecute()・・・doInBackgroundメソッドの処理が終了すると、 UIスレッドで呼び出されます。
- onCancelled()・・・タスクがキャンセルされると、 UIスレッドで呼び出されます。
AsyncTaskでProgressDialogを表示する際のキモは、以下の2点です。
- プログレスダイアログを表示している時にディスプレイの縦横を変更した時の処理
- プログレスダイアログをキャンセルした時の処理
AsyncTaskを継承したProgressTaskクラス
package com.example.helloandroid.service; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.SystemClock; public class ProgressTask extends AsyncTask<:Void,Integer,Boolean>{ private Context mContext; private ProgressDialog mProgressDialog; private Boolean isShowProgress; /** * コンストラクタ * @param context */ public ProgressTask(Context context){ mContext = context; } /** * getIsShowProgress * プログレスダイアログが表示中かどうかを返します。 * @return */ public Boolean getIsShowProgress() { return isShowProgress; } /** * onPreExecute * 最初にUIスレッドで呼び出されます。 * UIに関わる処理をします。 */ @Override protected void onPreExecute() { super.onPreExecute(); isShowProgress = true; showDialog(); } /** * doInBackground * ワーカースレッド上で実行されます。 * このメソッドに渡されるパラメータの型はAsyncTaskの一つ目のパラメータです。 * このメソッドの戻り値は AsyncTaskの三つ目のパラメータです。 * @return */ @Override protected Boolean doInBackground(Void... params) { for(int i=0; i<:10; i++){ SystemClock.sleep(1000); // キャンセルが押された場合 if (isCancelled()) { return false; } publishProgress((i+1) * 10); } return true; } /** * onProgressUpdate * doInBackground内でpublishProgressメソッドが呼ばれると、 UIスレッド上でこのメソッドが呼ばれます。 * このメソッドの引数の型はAsyncTaskの二つ目のパラメータです。 * @param values */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); mProgressDialog.setProgress(values[0]); } /** * onPostExecute * doInBackground が終わるとそのメソッドの戻り値をパラメータとして渡して onPostExecute が呼ばれます。 * このパラメータの型は AsyncTask を extends するときの三つめのパラメータです。 * バックグラウンド処理が終了し、メインスレッドに反映させる処理をここに書きます。 * @param result */ @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); dismissDialog(); isShowProgress = false; } /** * onCancelled * cancelメソッドが呼ばれるとonCancelledメソッドが呼ばれます。 */ @Override protected void onCancelled() { super.onCancelled(); dismissDialog(); isShowProgress = false; } /** * showDialog * プログレスダイアログを表示します */ public void showDialog() { mProgressDialog = new ProgressDialog(mContext); mProgressDialog.setMessage("データ読み込み中..."); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setIndeterminate(false); mProgressDialog.setMax(100); mProgressDialog.incrementProgressBy(0); mProgressDialog.setCancelable(true); mProgressDialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cancel(true); // 非同期処理をキャンセルする } }); mProgressDialog.show(); } /** * dismissDialog * ダイアログを終了する。 */ public void dismissDialog() { mProgressDialog.dismiss(); mProgressDialog = null; } }呼び出しもとのMainActivityクラス
package com.example.helloandroid.activity; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import com.example.helloandroid.R; import com.example.helloandroid.service.ProgressTask; public class MainActivity extends Activity { //Activityが破棄されても、オブジェクトを保持できるようにstaticで宣言する。 private static ProgressTask mTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //プログレスダイアログを再表示する。 if (mTask != null && mTask.getIsShowProgress()){ mTask.showDialog(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onPause() { //プログレスダイアログを閉じる。 if (mTask != null && mTask.getIsShowProgress()) { mTask.dismissDialog(); } super.onPause(); } public void button1Click(View view) { //時間のかかる処理を別スレッドで実行 mTask = new ProgressTask(this); mTask.execute(); } }ダイアログ表示中にディスプレイの縦横を切り替えるとダイアログが消えてしまいます。
これはディスプレイの縦横を変更すると呼び出し元のアクティビティが破棄され、新しい向きのActivityが生成されます。 そのためダイアログも消えてしまうようです。
またAsyncTaskの処理が終了した時点でIllegalArgumentExceptionが発生してしまいます。
これはダイアログのdismissメソッドを呼び出す時に、ダイアログを表示したアクティビティが破棄されているのが原因のようです。
詳しくはこちらに書かれています。
Tech Racho「Android: ダイアログを表示して縦横が変わるとdismissでエラー」
kasa0の部屋「ProgressDialogとAsyncTaskの甘い罠」
対策は
ProgressTaskクラスでダイアログ表示中かどうかの状態を管理します。
MainActivityクラスでProgressTaskオブジェクトをstatic変数で保持します。
MainActivityクラスのonPauseメソッドでプログレスダイアログを閉じます。
MainActivityクラスのonCreateメソッドでプログレスダイアログを表示します。
キャンセル時の処理について
キャンセルボタンクリック時にProgressTask#cancel(true)を呼びます。
doInBackgroundメソッドではキャンセルされたかどうかを見て、処理を行います。
キャンセルされるとonPostExecute()メソッドは呼ばれない為、onCancelledメソッドで終了処理を行います。
Android プログレスダイアログの表示
進捗状況を表示する水平スタイルのプログレスダイアログを表示します。
処理中かどうかを表示する水平スタイルのプログレスダイアログを表示します。
setIndeterminateメソッドにtrueを設定すると、処理中かどうかを表すプログレスバーになります。
setMax()メソッドやincrementProgressBy()メソッド、ementSecondaryProgressBy()メソッドの設定は無視されるようです。
円スタイルのプログレスダイアログを表示します。
setProgressStyle()メソッドにProgressDialog.STYLE_SPINNERを設定すると円スタイルになります。
setIndeterminate()メソッドやsetMax()メソッド、incrementProgressBy()メソッド、ementSecondaryProgressBy()メソッドの設定は無視されるようです。
public void button1Click(View view) { ProgressDialog dialog = new ProgressDialog(this); //タイトルを設定します。 dialog.setTitle("Title"); //メッセージを設定します。 dialog.setMessage("Message"); //水平バースタイルに設定します。 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //falseの場合、プログレスバーの進捗状況を表示します。 dialog.setIndeterminate(false); //最大値を設定します。 dialog.setMax(100); //進捗の値を設定します dialog.incrementProgressBy(30); //セカンダリ値を設定します dialog.incrementSecondaryProgressBy(70); //キャンセルできるかどうかです。 dialog.setCancelable(true); //ダイアログにキャンセルボタンを追加します。 dialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); //ダイアログを表示 dialog.show(); }
処理中かどうかを表示する水平スタイルのプログレスダイアログを表示します。
setIndeterminateメソッドにtrueを設定すると、処理中かどうかを表すプログレスバーになります。
setMax()メソッドやincrementProgressBy()メソッド、ementSecondaryProgressBy()メソッドの設定は無視されるようです。
public void button1Click(View view) { ProgressDialog dialog = new ProgressDialog(this); //タイトルを設定します。 dialog.setTitle("Title"); //メッセージを設定します。 dialog.setMessage("Message"); //水平バースタイルに設定します。 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //falseの場合、プログレスバーの進捗状況を表示します。 dialog.setIndeterminate(true); //最大値を設定します。 dialog.setMax(100); //進捗の値を設定します dialog.incrementProgressBy(30); //セカンダリ値を設定します dialog.incrementSecondaryProgressBy(70); //キャンセルできるかどうかです。 dialog.setCancelable(true); //ダイアログにキャンセルボタンを追加します。 dialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); //ダイアログを表示 dialog.show(); }
円スタイルのプログレスダイアログを表示します。
setProgressStyle()メソッドにProgressDialog.STYLE_SPINNERを設定すると円スタイルになります。
setIndeterminate()メソッドやsetMax()メソッド、incrementProgressBy()メソッド、ementSecondaryProgressBy()メソッドの設定は無視されるようです。
public void button1Click(View view) { ProgressDialog dialog = new ProgressDialog(this); //タイトルを設定します。 dialog.setTitle("Title"); //メッセージを設定します。 dialog.setMessage("Message"); //水平バースタイルに設定します。 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); //falseの場合、プログレスバーの進捗状況を表示します。 dialog.setIndeterminate(true); //最大値を設定します。 dialog.setMax(100); //進捗の値を設定します dialog.incrementProgressBy(30); //セカンダリ値を設定します dialog.incrementSecondaryProgressBy(70); //キャンセルできるかどうかです。 dialog.setCancelable(true); //ダイアログにキャンセルボタンを追加します。 dialog.setButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); //ダイアログを表示 dialog.show(); }
登録:
投稿 (Atom)
-
DataTableから重複を除くには と DataTableの集約計算を行う(Compute) を利用して、DataTableをグループ化し集計を行います。 以下のようなデータが入ったDataTableから、Field1とField2で重複を取り除き集計をおこないます。...
-
前回「 PLSQL SELECTの結果を取得する ~取得結果が1行の場合~ 」に続き 今回はSELECTの結果が複数行の場合です。 SELECTの結果が複数行の場合はカーソルを使用します。 カーソルとは SELECTの結果セットに対して、1行ずつデータを取り出し、順次...
-
datatableの集約計算を行うにはDataTable.Compute メソッドを使用します。 Dim As Object '最大値を求める value = datatable.Compute("Max(集計列名)", Nothing) ...