2012年3月31日土曜日

Spannable.SPAN_COMPOSING sample code

Spannable.SPAN_COMPOSING sample code

Spannable.SPAN_COMPOSINGは、既存の装飾を削除し、新たに装飾を設定するフラグです。

ただし、「既存の装飾を削除」にクセがあります。これに関してSpannable.SPAN_COMPOSING その2に書いておきました。

sample codeは下記のとおりです。
public class TextViewActivity extends Activity

    implements
    OnClickListener
    {
    final int iMaxChar = 300;
    int iCounter;
    Button bu;
    TextView tv;
    SpannableString ss;
    BackgroundColorSpan spanBC;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        int i;
        char c = '亜';
        StringBuilder sb;
        
        bu = (Button)findViewById(R.id.Button);
        bu.setOnClickListener(this);
        tv = (TextView)findViewById(R.id.TextView);
        
        //表示する文字列の作成
        sb = new StringBuilder();
        for(i=0; i<iMaxChar; i++) sb.append(c++);
        
        //装飾の作成
        ss = new SpannableString(sb.toString());
        spanBC = new BackgroundColorSpan(0xff880000);
        
        //第ゼロ番目の文字に装飾を施す。
        iCounter = 0;
        ss.setSpan(spanBC, iCounter, iCounter+1, Spannable.SPAN_COMPOSING);
        tv.setText(ss);
    }


    @Override
    public void onClick(View v) {
        if(v==bu){//クリックした場合
            iCounter++;//次の文字に移行する。
            if(iCounter>=iMaxChar) iCounter = 0;
            
            //前回の装飾は無くなり、次の文字が装飾される。
            ss.setSpan(spanBC, iCounter, iCounter+1, Spannable.SPAN_COMPOSING);
            tv.setText(ss);
            return;
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/Button"
        android:text="@string/Button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </Button>
    <TextView
        android:id="@+id/TextView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        > 
    </TextView>
</LinearLayout>

2012年3月25日日曜日

Could not find class 'com.google.ads.AdView'

Could not find class 'com.google.ads.AdView'

標題のエラーについては下記のサイトで解決策が掲示されています。
Libraries in SDK 17 - android
How to fix the “NoClassDefFoundError” with ADT 17
Dealing with dependencies in Android projects
この問題は、revision 17 of the Android SDK Tools and of the Eclipse ADT plug-inにおけるものであるとされています。

解決方法は次のとおりです。
プロジェクト名のフォルダー(プロジェクトルートのフォルダー)の直下に"libs"という名前のフォルダーを設けて、そのフォルダーにjarファイルをコピーしてください。そうすれば、jarファイルは自動的に"Android Dependencies"のフォルダーに組み込まれ、問題は解決します。

"libs"という名前のフォルダーは、「Package Explorer」欄で手入力で作成できます。

教科書で示されているような、EclipseにおけるProject > Properties > Java Build Path > Libralies > Add External JARs....といった操作は必要ではありません。
教科書:Google AdMob Ads Android Fundamentals

むしろ、(Project > Properties > Java Build Path > Libralies の)「JARS and class folders on the build path:」欄には、"Android 4.0.3"及び"Android Dependencies"の2個だけにしておかねばなりません。

そして、"libs"という名前のフォルダーにGoogleAdMobAdsSdk-4.3.1.jarファイルをコピーします。jarファイルをコピーする作業は、「Package Explorer」欄で行えます。

この場合の留意点として、"libs"フォルダーの直下にjarファイルを置かねばならないということです。"libs"フォルダーとjarファイルの中間に何らかのフォルダーが有ってはダメです。

正しいjarファイルの配置:
JPVoicer(プロジェクトルートのフォルダー)
|- libs(フォルダー)
  |- GoogleAdMobAdsSdk-4.3.1.jar

ダメなファイルの配置
JPVoicer(プロジェクトルートのフォルダー)
|- libs(フォルダー)
  |- GoogleAdMobAdsSdkAndroid-4.3.1(フォルダー)
    |- GoogleAdMobAdsSdk-4.3.1.jar

2012年3月18日日曜日

onTouch sample code

onTouch sample code

利用者がViewを操作した場合、その操作は当該Viewのみに限定されるのであって、他のView、例えば、親のViewに自動的に処理が移るというのではない。
もし、他のViewに処理を移し替えたい場合には、そのようにcodeを書かなければならない。

public class OnTouchActivity extends Activity
    implements
    OnTouchListener,
    OnClickListener
    {
    TextView tvValue, tvResult;
    Button buMain, buSub;
    boolean bReturnTrue;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tvValue = (TextView)findViewById(R.id.TextReturnValue);
        tvResult = (TextView)findViewById(R.id.TextResult);
        buMain = (Button)findViewById(R.id.ButtonMain);
        buMain.setOnClickListener(this);
        buSub = (Button)findViewById(R.id.ButtonSub);
        buSub.setOnTouchListener(this);
        buSub.setOnClickListener(this);
        DisplayValue(false);
    }
    
    void DisplayValue(boolean b){
        String s;
        bReturnTrue = b;
        if(b==true) s= "Return Value onTouch : true";
        else s = "Return Value onTouch : false";
        tvValue.setText(s);
    }
    
    /*
     * onClickメソッドの実行の前に、onTouchメソッドが実行される。
     * onTouchメソッドにおいてfalseを返した場合、そのViewを引数とするonClickメソッドが呼ばれる。
     * trueを返した場合、onClickメソッドは呼ばれない。
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        tvResult.setText("");
        if(v==buSub){
            if(bReturnTrue==true){
                //trueを返すことによりbuSubのonClickメソッドは呼ばれなくなる。
                return true;
            }
        }
        return false;
    }


    //onTouchメソッドにおける戻値がfalseの場合に、onClickメソッドが呼ばれる。
    @Override
    public void onClick(View v) {
        if(v==buMain){
            if(bReturnTrue==true) DisplayValue(false);
            else DisplayValue(true);
            return;
        }
        
        //buSubのonTouchメソッドの戻値がtrueの場合、onClickメソッドは呼ばれない。
        if(v==buSub){
            tvResult.setText("onClick : ButtonSub");
            return;
        }
    }
}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <Button
        android:id="@+id/ButtonMain"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/ButtonMain"
        >
    </Button>
    <TextView
        android:id="@+id/TextReturnValue"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </TextView>
    <Button
        android:id="@+id/ButtonSub"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/ButtonSub"
        >
    </Button>
    <TextView
        android:id="@+id/TextResult"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </TextView>
</LinearLayout>

2012年3月14日水曜日

TextViewの任意の位置にスクロールさせる

TextViewの任意の位置にスクロールさせる

参考
AndroidのScrollViewで一番下までスクロールさせるには
ScrollViewを一番下まで自動でスクロールする方法
Scroll TextView to text position
TextView#getLineCountメソッドの戻値がゼロ

ScrollViewを使って、TextViewの任意の位置までスクロールさせるプログラムです。
このプログラムでは、TextViewに設定する大量の文字列群内の中央の文字列に赤色を付けて、その赤色の文字列が存在する中央の位置まで画面をスクロールさせます。

Javaのsample codeは次のとおりです。

public class ScrollTextActivity extends Activity
    implements
    OnClickListener
    {
    Button bu;
    TextView tv;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        SpannableStringBuilder sb;
        int i, j;
        BackgroundColorSpan spanBC;
        final String sData = "あいうえお";
        
        bu = (Button)findViewById(R.id.Button);
        bu.setOnClickListener(this);

        //適当に文字列データを作成する。
        spanBC = new BackgroundColorSpan(0xff880000);
        
        sb = new SpannableStringBuilder();
        for(i=0, j=0; i<300; i++, j++) sb.append(sData);
        j *= sData.length();
        for(i=0; i<300; i++) sb.append(sData);
        sb.setSpan(spanBC, j, j+sData.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        
        tv = (TextView)findViewById(R.id.TextView);
        tv.setText(sb);
        
        //onCreateメソッドが実行される時点ではスクロールはできない。
        //ScrollView sv;
        //sv = (ScrollView)findViewById(R.id.ScrollView);
        //sv.smoothScrollTo(0, 500);//効果の無いコマンド
    }
    
    @Override
    public void onClick(View v) {
        if(v==bu){
            //Viewが作成された後で、スクロールが可能になる。
            ScrollView sv;
            int iLine, iPixel, iHeight, i;
            
            sv = (ScrollView)findViewById(R.id.ScrollView);
            iLine = tv.getLineCount ();
            iLine /= 2;
            iPixel = tv.getLineHeight ();
            iHeight = sv.getHeight ();
            i = iLine * iPixel;
            i -= iHeight / 2;
            sv.smoothScrollTo(0, i);//実行可能
        }
    }
}

xmlは次のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <Button
        android:id="@+id/Button"
        android:text="@string/Button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </Button>
    <ScrollView
        android:id="@+id/ScrollView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
        <TextView
            android:id="@+id/TextView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
        </TextView>
    </ScrollView>
</LinearLayout>

SimpleAdapterのsample code

SimpleAdapterのsample code

文字列を代入し、色を付けたTextViewを一覧にして表示するSimpleAdapterのsample codeです。

main.xmlは次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
    <TextView
        android:id="@+id/TextView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </TextView>
</LinearLayout>


Javaのcodeは次のとおりです。

public class SimpleAdapterActivity extends ListActivity{
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        String sFrom[] = {"String", "Color"};
        int iTo[] = new int[]{R.id.TextView, R.id.TextView};
        ArrayList<Map<String, Object>> data =new ArrayList<Map<String, Object>>();
        SimpleAdapter sa;
        SimpleAdapter.ViewBinder savb;
        
        savb = new SimpleAdapter.ViewBinder(){
            @Override
            public boolean setViewValue(View view, Object data, String s){
                if(view.getId()==R.id.TextView){
                    TextView tv;
                    tv = (TextView)view;
                    if(data.getClass().equals(String.class)==true){
                        String sData;
                        
                        sData = (String)data;
                        tv.setText(sData);
                        return true;
                    }
                    if(data.getClass().equals(Integer.class)==true){
                        Integer iData;
                        
                        iData = (Integer)data;
                        tv.setBackgroundColor(iData.intValue());
                        return true;
                    }
                }
                return false;
            }
        };
        
        //適当にデータを作成する。
        Map<String, Object> m;
        m = new HashMap<String, Object>();
        m.put("String", "Red");
        m.put("Color", 0xffff0000);
        data.add(m);
        m = new HashMap<String, Object>();
        m.put("String", "Green");
        m.put("Color", 0xff00ff00);
        data.add(m);
        m = new HashMap<String, Object>();
        m.put("String", "Blue");
        m.put("Color", 0xff0000ff);
        data.add(m);
        
        sa = new SimpleAdapter(this, data, R.layout.main, sFrom, iTo);
        sa.setViewBinder(savb);
        setListAdapter(sa);
    }
}

2012年3月13日火曜日

Spannable.SPAN_PARAGRAPH

Spannable.SPAN_PARAGRAPH

Spannable.SPAN_PARAGRAPHを使ったsample codeは次のとおりです。

public class TextViewActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        SpannableString ss;
        SpannableStringBuilder ssb;
        BackgroundColorSpan spanRed, spanGreen, spanBlue;
        TextView tv;
        
        ss = new SpannableString("aaa\nbbb\nccc\nddd\n");
        ssb = new SpannableStringBuilder();
        spanRed = new BackgroundColorSpan(0xff880000);
        spanGreen = new BackgroundColorSpan(0xff008800);
        spanBlue = new BackgroundColorSpan(0xff000088);
        ss.setSpan(spanRed, 4, 8, Spannable.SPAN_PARAGRAPH);
        ss.setSpan(spanGreen, 8, 12, Spannable.SPAN_PARAGRAPH);
        ss.setSpan(spanBlue, 12, 16, Spannable.SPAN_PARAGRAPH);
        ssb.append(ss);
        
        spanRed = new BackgroundColorSpan(0xff880000);
        ssb.append("eee\n");
        ssb.setSpan(spanRed, 16, 20, Spannable.SPAN_PARAGRAPH);
        ssb.append("fff\n");
        
        tv = (TextView)findViewById(R.id.TextView);
        tv.setText(ssb);
    }
}

このプログラムを実行すると次のように画面に表示されます。
aaa
bbb
ccc
ddd
eee
fff

SPAN_EXCLUSIVE_EXCLUSIVE

SPAN_EXCLUSIVE_EXCLUSIVE

SpannableStringBuilder#setSpanメソッドの第四番目の引数の意味が不明だったため、調べました。

Corgiさんのspanの適用範囲の設定に解答がありました。
そこに書かれている内容を検証するプログラムを作りました。

public class TextViewActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String s;
        SpannableStringBuilder ssb;
        BackgroundColorSpan spanBCEE, spanBCEI, spanBCIE, spanBCII, spanBCNothing;
        TextView tv;
        
        s = getString(R.string.hello);
        ssb = new SpannableStringBuilder();
        ssb.append(s);
        spanBCEE = new BackgroundColorSpan(0xff880000);
        spanBCEI = new BackgroundColorSpan(0xff880000);
        spanBCIE = new BackgroundColorSpan(0xff880000);
        spanBCII = new BackgroundColorSpan(0xff880000);
        spanBCNothing = new BackgroundColorSpan(0xff880000);
        ssb.setSpan(spanBCEE, 2, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        ssb.setSpan(spanBCEI, 7, 9, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        ssb.setSpan(spanBCIE, 12, 14, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        ssb.setSpan(spanBCII, 17, 19, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
        ssb.setSpan(spanBCNothing, 17, 19, 0);
        
        ssb.insert(24, "*");
        ssb.insert(22, "*");
        ssb.insert(19, "*");
        ssb.insert(17, "*");
        ssb.insert(14, "*");
        ssb.insert(12, "*");
        ssb.insert(9, "*");
        ssb.insert(7, "*");
        ssb.insert(4, "*");
        ssb.insert(2, "*");
        
        tv = (TextView)findViewById(R.id.TextView);
        tv.setText(ssb);
    }
}

上記プログラムによって、画面には次のように表示されます。

He*ll*o W*or*ld,* T*ext*Vi*ewA*ct*ivity!

次に、挿入を、範囲の内側に実施した場合の実験をしてみました。挿入部分のcodeは次のとおりです。
        ssb.insert(23, "*");
        ssb.insert(18, "*");
        ssb.insert(13, "*");
        ssb.insert(8, "*");
        ssb.insert(3, "*");
この結果は次のとおりです。

Hel*lo Wo*rld, *TextV*iewAc*tivity!

以上のことから、Corgiさんが説明するように、「spanの適用範囲の直前直後に関する設定」ということが言えます。

挿入をすることによって意味を成すオプションであるため、SpannableStringBuilder#setSpanでは使えますが、SpannableString#setSpanでは意味の無いオプションであるように思えます。

第四番目の引数にゼロを代入した場合、装飾が表示されないため、何か値を代入しておかなければならないということです。

Spannable.SPAN_MARK_MARKは、Spannable.SPAN_INCLUSIVE_EXCLUSIVEと同じConstant Value 17 (0x00000011)です。


Spannable.SPAN_POINT_POINTは、Spannable.SPAN_EXCLUSIVE_INCLUSIVEと同じConstant Value 34 (0x00000022)です。

2012年3月12日月曜日

複雑な形状のViewの一覧を作成する

複雑な形状のViewの一覧を作成する

ListViewを使えば複雑な形状のViewの一覧を作成できる。
参考:SimpleAdapterのsample code
しかし、この技法の欠点は、書き込み可能なView、例えば、EditTextを配置しても、そのEditTextに対して利用者が書き込みを行うことはできない、ということである。
ListViewのような作り込まれたものは、プログラミングが終わった後で、予期しない不都合が判明する。

素直に、ScrollView & LayoutInflaterを使って、地道に作成する。

ただし、この場合、EditTextにはIDを与えてはいけない、という点に留意しなければならない。
例えば、次のxmlのように、android:id="@+id/EditText"を設けてはいけない。削除しよう。
    <EditText
        android:id="@+id/EditText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </EditText>

仮に、IDを設けたとしても、初回起動時には、上手く表示される。しかし、configuration changeに伴う再起動が発生した後で表示されるEditTextには、全て同一の文字列が代入されてしまう。
この問題を避けるために、ID指定を書いてはいけないのである。
TextViewの場合はID指定をしても問題は発生しない。

main.xmlは次のとおりである。IDがParentListのLinearLayoutに、複数の子Viewを動的に追加する。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
        <LinearLayout
            android:id="@+id/ParentList"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >
        </LinearLayout>
    </ScrollView>>
</LinearLayout>

上記のxmlの中に、次のlistitem.xmlを動的に挿入する。各ViewにはIDを付けていない。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="2dp"
    android:background="#555"
    >
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="#000"
        >
        <CheckBox
            android:text="@string/Apply"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
        </CheckBox>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
            <TextView
                android:text="@string/Before"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            >
            </TextView>
            <EditText
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                >
            </EditText>
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
            <TextView
                android:text="@string/After"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            >
            </TextView>
           <EditText
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                >
            </EditText>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

上記2個のxmlを使って、複数のViewを動的に生成し、一覧を作成するJavaのcodeは次のとおりである。ViewのIDが存在しないため、個々のViewの識別はアドレス(相対位置と表現して良いかもしれない)で行う。
public class InflateListActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); 
        setContentView(R.layout.main);
        
        int i;
        ArrayList<String> al;
        BackupData bd;
        
        bd = (BackupData)getLastNonConfigurationInstance();
        if(bd==null){
            //サンプルプログラムなので適当にデータを代入する。
            al = new ArrayList<String>();
            al.add("true");
            al.add("Green");
            al.add("Blue");
            al.add("false");
            al.add("Green");
            al.add("Blue");
            al.add("true");
            al.add("Green");
            al.add("Blue");
            al.add("false");
            al.add("Red");
            al.add("Blue");
            al.add("true");
            al.add("Yellow");
            al.add("Red");
        }
        else{//configuration changeに伴う再起動
            al = bd.getBackupData();
        }
        
        for(i=0; i<al.size()/3; i++){
            LayoutInflater inf;
            LinearLayout llParent, ll, ll2, llChild;
            CheckBox cb;
            EditText et;
            String s;
            
            //親Viewを取得する。
            llParent = (LinearLayout)findViewById(R.id.ParentList);
            
            //挿入する子Viewを作成する。
            inf = getLayoutInflater();
            ll = (LinearLayout)inf.inflate(R.layout.listitem, null);
            
            ll2 = (LinearLayout)ll.getChildAt(0);
            
            //子Viewにデータを入れる。
            cb = (CheckBox)ll2.getChildAt(0);
            s = al.get(i*3);
            if(s.equals("true")==true) cb.setChecked(true);
            else cb.setChecked(false);
            
            llChild = (LinearLayout)ll2.getChildAt(1);
            et = (EditText)llChild.getChildAt(1);
            et.setText(al.get(i*3+1));
            
            llChild = (LinearLayout)ll2.getChildAt(2);
            et = (EditText)llChild.getChildAt(1);
            et.setText(al.get(i*3+2));
            
            //親Viewに子Viewを入れる。
            llParent.addView(ll);
        }
    }
    
    //configuration changeに伴う再起動への対応
    @Override
    public Object onRetainNonConfigurationInstance(){
        ArrayList<String> al;
        BackupData bd;
        LinearLayout llParent;
        int i, iSize;
        
        al = new ArrayList<String>();
        llParent = (LinearLayout)findViewById(R.id.ParentList);
        iSize = llParent.getChildCount();
        for(i=0; i<iSize; i++){
            LinearLayout ll, ll2, llChild;
            CheckBox cb;
            EditText et;
            String s;
            
            ll = (LinearLayout)llParent.getChildAt(i);
            ll2 = (LinearLayout)ll.getChildAt(0);
            
            cb = (CheckBox)ll2.getChildAt(0);
            if(cb.isChecked()==true) s = "true";
            else s = "false";
            al.add(s);
            
            llChild = (LinearLayout)ll2.getChildAt(1);
            et = (EditText)llChild.getChildAt(1);
            s = et.getText().toString();
            al.add(s);
            
            llChild = (LinearLayout)ll2.getChildAt(2);
            et = (EditText)llChild.getChildAt(1);
            s = et.getText().toString();
            al.add(s);
        }
        
        bd = new BackupData();
        bd.setBackupData(al);
        return bd;
    }
    
    private class BackupData{
        private ArrayList<String> dataBackup;
        void setBackupData(ArrayList<String> al){
            dataBackup = al;
        }
        ArrayList<String> getBackupData(){
            return dataBackup;
        }
    }
}