2010-12-05

mediaplayerを作ってみる(10)-1

今回は、見た目の変更と前から気になってたのを追加。
参考は、
rTAKI's android ブログ

SDカードの中身を ListView を使って表示&選択 (拡張子フィルター付)


Tech Booster

Android Wiki*

後は、free icon。参考まで。


とりあえず気になっていた分から。
ActivityのonCreate内、setContentViewの次に

  String SDstatus = Environment.getExternalStorageState();

        // SDカードがセットされているか確認
        if (SDstatus.equals(Environment.MEDIA_MOUNTED) == false) {

          AlertDialog.Builder builder = 
      new AlertDialog.Builder(SDMediaPlayerActivity.this);

          builder.setTitle("警告");
          builder.setMessage("SDカードがセットされていません。");
          builder.setPositiveButton("OK", new DialogInterface.OnClickListener () {

            //@Override
            public void onClick(DialogInterface dialog, int which) {
             SDMediaPlayerActivity.this.finish();
            }
          });
          builder.show();
        }

まんまです。相変わらず。一応あった方がいいかなーと。

で、見た目はspinnerのdropdownlist。radiobuttonを変えるだけ。
まずは、button(icon)の用意。さっきのサイトでもいいですし、作るのもあり。
僕は、残念な感じのしか作れなかったので・・・。

で、用意したbuttonをres/drawableに。3つある理由はここを参考に。
ちょっと試した結果、is01だと、32x32をdrawable-hdpiに置いとくと
なんかいい感じなので、そのように致しました。まあ、お好みで。

で、まずはselector。res/drawableに配置。とりあえず同じとこに。

radiobutton_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 <item
  android:state_checked="true"
  android:drawable="@drawable/button_purple" />
</selector>


checkされてるとこしかbuttonを表示しない。まあ、お好みで。
button_purple は、用意したbuttonの名前に変えてください。
次は、style。res/valuesに配置。

radiobutton_style.xml

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <style name="custom_radiobutton" parent="android:Widget.DropDownItem">
        <item name="android:checkMark">@drawable/radiobutton_selector</item>
    </style>
</resources>

ほいから、layout。res/layoutに配置。

dropdownlist.xml

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/text1"
  style="@style/custom_radiobutton"
  android:layout_height="?android:attr/listPreferredItemHeight"
  android:layout_width="fill_parent"
  android:singleLine="true"
  android:textSize="16sp"
  android:ellipsize="marquee">
</CheckedTextView>

最後に、ActivityのonCreate内の

spinnerAdapter.setDropDownViewResource(
    android.R.layout.simple_spinner_dropdown_item); を、

spinnerAdapter.setDropDownViewResource(R.layout.dropdownlist);

に変更。こんな↓感じ。










Tech Boosterさんのボタンいいなー、何て思ってたら見つけちゃったので。
ほんとは、色も変えたかったんですが枠の色の変え方がわからないので。保留。

次は、やっとフォルダをまたいでの連続再生。今度はほんと。現在進行中。
まあ、ぼちぼち。

2010-12-04

mediaplayerを作ってみる(9)-2

また、地味に変更。思いつきでAndroid2.2のエミュレーターで動かしたら
強制終了。ほっといても良かったんですが。is01は1.6なので。
なんか引っかかって。こちら↓を参考に

Android 1.xと2.2の互換性について



dirListMakerを


public ArrayList<String> dirListMaker(ArrayList<String> list, String ext) {
//ArrayListの生成
ArrayList<String> array = new ArrayList<String>();

int m = 0; int n = 0;
        while (list.size() > m) {
        
         File subDir = new File(list.get(m));
         try {
         String[] subFileName = subDir.list();
        n = 0;
        while (subFileName.length > n) {
        File subFile = new File(subDir.getPath() + FILE_SEP + subFileName[n]);
       
        if (subFile.isDirectory()) {
        list.add(subDir.getPath() + FILE_SEP + subFileName[n]);
       
        } else if (subFile.isFile() && subFile.getName().endsWith(ext)) {
       
        if (!array.contains(list.get(m))) {
        array.add(list.get(m));
        }
        }
        n++;
        }
         } catch (NullPointerException e) {
         /*Android2.2ではString[] subFileName = subDir.list();において
         * ディレクトリが空の場合nullを返します。
         * そのExceptionを回避するためのtry-catchなので
         処理をしません。*/
         }
         m++;
        }
        return array;
}

try-catchで括っただけ。これで、いけました。エミュレーターでは。
もう一つの方も変更しときました。使ってませんが。
後もう一ヶ所変更。特につながりはありませんが。
javaの道の文字列-6.文字列の分割を参考に。

ActivityのonCreate内でspinnerAdaperにaddしてるとこ↓を


        int n = 0;
        for(String name : musicDirList) {
         ++n;
         spinnerAdapter.add(n + ":" + name);
        }

この様に↓

        //ちょっとした準備
        ArrayList<String[]> dirNameList = new ArrayList<String[]>();
        for (String fileName : musicDirList) {
         String[] strArray = fileName.split(File.separator);
         dirNameList.add(strArray);
        }
        
        //ディレクトリ2階層分だけ表示。SD直下にある時は1階層だけ。
        int n = 0;
        for(String[] nameList : dirNameList) {
         int size = nameList.length;
         if (size < 3) {
         spinnerAdapter.add((n + 1) + ":" + "/" + nameList[size - 1]);
         } else {
         spinnerAdapter.add((n + 1) + ":" + "/" + nameList[size - 2] + "/" + nameList[size - 1]);
         }
         n++;
        }

階層が深くなったときに表示しきれなくなってたので。
もっと他にやりようがあるような気もしますが。
layoutを作るとか、adapterを作るとか。

次は、いや次も、なんか適当に。たぶん。

2010-12-03

mediaplayerを作ってみる(9)

今回も、修正とちょっと改造。なかなか先に進まない。
色々修正してから進んだ方が、後が楽かなーと。
で、MusicPlayerから。

    public void setTitle() {
        titleView.setText((dirNum + 1) +
                "-" + (musicNum + 1) + ":" + musicList.get(musicNum));
    }

タイトルにディレクトリの番号を追加。Activityは、

        //spinnerの取得とArrayAdapterの生成及びセット
        spinner = (Spinner)findViewById(R.id.spinner);
        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item);
       
        int n = 0;
        for(String name : musicDirList) {
            ++n;
            spinnerAdapter.add(n + ":" + name);
        }

spinnerに番号追加。こんな簡単とは。なんだかなー。
そいで、onItemSelectedの最後に

changeMusicFlag = false;

追加。最後じゃなくてもいいかも。未確認。
それから、

    //色々セットして再生
    public void setAndPlayMusic() {
       
        //ディレクトリが変わってたらmusicFileList(MusicPlayerが参照してる方)
        //の中身を詰め替え。listViewと同じにする。
        if (spinnerPosition != musicPlayer.getDirNum()) {
            musicFileList.clear();
            for (String fileName : fileListForListView) {
                musicFileList.add(fileName);
            }
            musicPlayer.setDirNum(spinnerPosition);
        }

        musicPlayer.setMusicNum(listPosition);
        musicPlayer.playMusic();
        changeMusicFlag = false;           
    }

こんなメソッドを作成。同じのが、3回出てきたので。まとめただけ。
どっか適当に置いといてください。
そして、onItemClick

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        //2度押しで再生。基本、再生ボタンと同じ。
        if (changeMusicFlag && startFlag && position == listPosition) {
           
            setAndPlayMusic();
           
        } else {
            //曲の選択をするだけ。再生はしない。とりあえず。
            listPosition = position;
            musicNum_listClicked = musicPlayer.getMusicNum();
            changeMusicFlag = true;
            startFlag = true;//1曲目なんか選択されたら。それだけのため。
        }        
    }

リストビュー2度押しで再生出来るようにしました。1度では再生しない。
あえて。 そいから、onClickStartの中、

if (!musicPlayer.isPlaying()){
           
            //停止中にlistViewで曲変更した場合
            if (changeMusicFlag) {
               
                setAndPlayMusic();
            }

さっきのメソッドに変えただけ。同じく、

//再生中で曲選択が変わってたら。つまり、listViewで選択した場合です。
        if (changeMusicFlag && musicNum_listClicked == musicPlayer.getMusicNum()) {   

            setAndPlayMusic();

場所分かるかな。まあ、何とか探してください。
も一つ、

    public void onClickPause(View view) {
        if (musicPlayer.isPlaying()) {
            musicPlayer.pause();
            pauseFlag = true;    //ここのみtrueに。
        } else {
            if (pauseFlag) {
                musicPlayer.start();
                pauseFlag = false;
            }
        }
    }

一時停止ボタンでも、pause解除出来るようにしました。
最後に、setTitle

titleView.setText((musicPlayer.getDirNum() + 1) +
                "-" + (n + 1) + ":" + musicFileList.get(n));

ディレクトリの番号を追加。MusicPlayerと同じく。
リストと再生中の曲のディレクトリが違う状況では、
番号が合った方がいいかなーと。

だいぶ修正したけども、まだ修正出来てないとこも。

一時停止してホームボタンを押す。
起動する。
再生する。

と、なんか一曲進むときが。進まない時もある。
onPauseとか、onResumeとか、よくわかってないんで。
なんか、そのせいだと思ってるけど。ちがうかも。
これは、ほっとく。たぶん。そのうち。いずれ。また。

次は、次こそ、ディレクトリをまたいでの連続再生。
前作ったのの遺産がまだあるので、たぶん大丈夫。
なので、おまけも。まあ、予定は未定で。

2010-12-02

javaのメモ(1)

忘れないうちにメモ。参照。忘れてた。

mediaplayerの(8)-2の段階のイメージ図











あくまでイメージ図。

listViewが参照してるlistとmusicPlayerが参照しているlistが同じ。
なので、 spinner のイベントでlistを詰め替えると
musicPlayerの連続再生でplayMusicが呼ばれたときに
変更されてるlistを参照することになる。

なので、参照するlistを別物に













してやると、spinnerのイベントでlistが詰め替えられても
musicPlayerの参照しているlist2は変更されない。
連続再生でplayMusicが呼ばれてもlist2の次の曲が再生される。
もちろん、ディレクトリの情報とかもちゃんと管理しないとダメですが。

(8)-3の変更の主要な部分はこれ。後は、list と list2を同期(?)させる
タイミング。多分できてると思うけど。まあ、穴はどっかにありそうですが。

なんか、力技。高校のころの数学とかと変わってない。
ゴリゴリ計算していくだけ。華麗さと言うか、美しさが無い。

なんかもっと、綺麗に出来そうな気が。僕には無理ですが。

追記

musicDirListの方は、起動中は中身が変わらないので
番号だけ変えればOK。そんだけ。

mediaplayerを作ってみる(8)-3

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO 自動生成されたメソッド・スタブ
       
    }
前回の最後にも追記しておきましたが、一応。忘れてました。
なんかよく分かりませんが、eclipseに言われたので。

で、修正。してみました。今後への布石も兼ねて。
なので、(9)ではなく(8)-3です。

まずは、MusicPlayer。フィールドは、

private String musicDirName; 削除。

    private ArrayList<String> dirList;
    private int dirNum;

追加。 コンストラクタに

dirNum = 0; 追加。フィールドで初期化でもいいような・・・。

で、ゲッター、セッターが

    public ArrayList<String> getMusicList() {
        return musicList;
    }
   
    public void setMusicList(ArrayList<String> array) {
        musicList = array;
    }
   
    public void setDirList(ArrayList<String> array) {
        dirList = array;
    }
   
    public void setListView(ListView lv) {
        listView = lv;
    }
   
    public int getDirNum() {
        return dirNum;
    }
   
    public void setDirNum(int n) {
        dirNum = n;
    }
   
    public int getMusicNum() {
        return musicNum;
    }
   
    public void setMusicNum(int num) {
        musicNum = num;
    }

追加じゃなくて、全部でこれだけ。要らないのもあるかも。
あまり気にしない。ほいで、playMusicの中を一部変更。

          listView.clearChoices();
        //再生中の曲のディレクトリと表示されてるディレクトリが同じなら
        if (dirNum == SDMediaPlayerActivity.getSpinnerPosition()) {
            listView.setItemChecked(musicNum, true);
            if (musicNum == 0) listView.setSelection(musicNum);
            else listView.setSelection(musicNum - 1);
        }
       
        try{
            super.setDataSource(dirList.get(dirNum)
                    + FILE_SEP + musicList.get(musicNum));

こんな感じに変更。敢えて分かりにくく。なんとなく。
 そいで、Activity。フィールドから
変更    private ArrayList<String> musicFileList;//musicPlayer用ファイルのリスト
追加
    private ArrayList<String> fileListForListView;//listView用ファイルリスト
private boolean startFlag;//1曲目用
    private static int spinnerPosition;//表示されているディレクトリの番号。static。

onCreate内

musicDirList = dlm.dirListMaker(dirList, "mp3"); の下に
        dirList = null; 追加。いや、なんとなく。もう要らないので。

         //musicFileListの生成
        musicFileList = new ArrayList<String>(); 削除。


        //fileListForListViewの生成
        fileListForListView = new ArrayList<String>(); 追加。と言うか変更。


startFlag = false; 追加。

それから、

    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        //選択されたアイテムの取得。
        musicDirName = musicDirList.get(position);
        spinnerPosition = position;
       
        //リストの詰め替え準備
        fileListForListView.clear();
        //リストの詰め替え
        flm.fileListMaker(musicDirName, "mp3", fileListForListView);
        if (musicFileList == null) {
            musicFileList = new ArrayList<String>();
            for (String fileName : fileListForListView){
                musicFileList.add(fileName);
            }
        }
        //listViewの変更
        listView.setAdapter(listAdapter);

        //色々通知。
        musicPlayer.setDirList(musicDirList);
        musicPlayer.setMusicList(musicFileList);
        musicPlayer.setListView(listView);
       
        //再生中の曲のディレクトリと同じだったら
//タイトルの色を変えてリストの2番目に持ってくる。
        if (spinnerPosition == musicPlayer.getDirNum() && startFlag) {
            listView.clearChoices();
            listView.setItemChecked(musicPlayer.getMusicNum(), true);
            if (musicPlayer.getMusicNum() == 0)
                        listView.setSelection(musicPlayer.getMusicNum());
            else listView.setSelection(musicPlayer.getMusicNum() - 1);
        }
    }

に変更。長くなり始めてる。今後もっと長くなるかも。
 も一つ。onItemClick内に

startFlag = true;//1曲目なんか選択されたら。それだけのため。

追加。まだまだ。onClickStartを

    public void onClickStart(View view) {
       
        if (!musicPlayer.isPlaying()){
           
            //停止中にlistViewで曲変更した場合
            if (changeMusicFlag) {
               
                if (spinnerPosition != musicPlayer.getDirNum()) {
                    musicFileList.clear();
                    for (String fileName : fileListForListView) {
                        musicFileList.add(fileName);
                    }
                    musicPlayer.setDirNum(spinnerPosition);
                }

                musicPlayer.setMusicNum(listPosition);
                musicPlayer.playMusic();
                changeMusicFlag = false;
            }
           
            if (pauseFlag) {    //一時停止中なら
               
                musicPlayer.start();
                pauseFlag = false;
               
            } else {
                if (startFlag) {
                    musicPlayer.playMusic();
                    changeMusicFlag = false;
                }
            }
        }
        //再生中で曲選択が変わってたら。つまり、listViewで選択した場合です。
        if (changeMusicFlag && musicNum_listClicked ==
                    musicPlayer.getMusicNum()) {   

            if (spinnerPosition != musicPlayer.getDirNum()) {
                musicFileList.clear();
                for (String fileName : fileListForListView) {
                    musicFileList.add(fileName);
                }
                musicPlayer.setDirNum(spinnerPosition);
            }

            musicPlayer.setMusicNum(listPosition);
            musicPlayer.playMusic();
            changeMusicFlag = false;           
        } else {
            changeMusicFlag = false;
        }
    }

どこと書くのが、面倒なくらい変更。したような気がしたので。全部載せときます。
 最後に、

    public static int getSpinnerPosition() {
        return spinnerPosition;
    }

staticなメソッド。たぶん合ってると思う。staticで。あまり使いたくない。static。
なんとなく。static final は好きだけど。なんとなく。

java。というか、参照とかを意識してなかったのが良くなかったと思う。
たぶん。まあ、なんかよく分かってないけど。

次も、地味に変更予定。ディレクトリをまたいでの連続再生は後回し。
まあ、予定は未定。