2014年2月5日

貯めマスっち アップデート

貯めマスっち アップデート

貯金ができるようにとゆるキャラで挑んだアプリ"貯めマスっち"

アプリ利用者の方から要望がありました。

貯めマスっち
貯めマスっちという貯金キャラが応援してくれて
日々マスをタッチしていってマスを埋めていく感覚で
貯金をしていくというシンプルなものです。
《ご要望》
・目標タスク別に設定できるようにしてほしい。


アプリを公開して4ヶ月順調にDL数は伸びるものの、若干停滞気味。

このままでいいのかというのを考えていた矢先でした。

要望を頂き、対応することにしました。

シンプルな要望に対して、プログラム上は解決しなければいけない問題が多くありました。

  1. データ保存方法
  2. データ取得方法
  3. 画面構成
  4. 利用中のデータ引継ぎ方法

1.データ保存方法について

問題:SharedPreferencesデータ保存の為、複雑なデータは向かない。
解決方法:SQLiteを採用

現状では保存すべきデータは3つだった為、SharedPreferencesで十分でした。
要望の項目を増やすということはデータ保存数がユーザーによって変わる為、
SQLiteを採用しました。このことは次の取得方法にも関わります。


2.データ取得方法

問題:SharedPreferencesではタスクごとに関連するデータを引き出せない。
解決方法:SQLiteを採用

やはりデータ取得もデータベースを使用します。

複数の項目に対して、それに対応する値を引き出すにはデータベースは必須でしょう。

3.画面構成

現状:目標タスクを選択するような画面が無い
解決方法:ActionBarのリストナビゲーションを使用

大幅な画面構成の変更は勇気がいることでした。
がらっと印象が変わりアプリらしくなったといえばなったような?
アップデート前
アップデート後

4.利用中のデータ引継ぎ

問題:データ保存、取得方法が変わる為、旧データが使えない。
解決方法:旧データを取得し、SQliteデータベースに初回だけ記録させる

旧データがSharedPreferences、新データがSQLite
共存させる訳にもいかず、旧データにフラグを所持させて
フラグが立ってない(既存ユーザー)のデータだけデータベースに記録させることで回避。


マンネリ化していたアプリ作りにユーザーからの要望という良い刺激、励みになりました。

ありがとうございました。



2014年1月14日

AdapterContextMenuInfoとは

AdapterContextMenuInfo

ContextMenuの選択されたアイテム情報(idやposition)を取得するときに使用します。

ContextMenuInfoの項がそのままですが再度掲載します。

getIdとかgetPositionとしがちですが、AdapterContextMenuInfo.positionまたはidでいいです。

以下ソース例ではpositionを取得します。


ListView表示
ContextMenu表示
ContextMenu選択
















MainActivity.java
public class MainActivity extends Activity{
 static final int CONTEXT_MENU1_ID = 0;//ContextMenuアイテムid
 static final int CONTEXT_MENU2_ID = 1;//ContextMenuアイテムid
 private AdapterContextMenuInfo adapterInfo;
 private ListView _contextlistView;
 private String _listitem;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 
  ListView _listview = (ListView) findViewById(R.id.listView1);
 
  String[] _stTest = { "テスト1", "テスト2", "テスト3"};//ListVieの表示アイテム
 
        ArrayAdapter<string> adapter = new ArrayAdapter<string>(this,
                android.R.layout.simple_list_item_1, _stTest);

        _listview.setAdapter(adapter);//アダプターセット
     
        registerForContextMenu(_listview);//ContextMenu登録
     
 }

 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
     super.onCreateContextMenu(menu, view, info);
     adapterInfo = (AdapterContextMenuInfo) info;
    
     _contextlistView = (ListView) view;
     _listitem = (String) _contextlistView.getItemAtPosition(adapterInfo.position);//list選択アイテム名を取得
    
     menu.setHeaderTitle("menu");//メニュータイトル
     //Menu.add(int groupId, int itemId, int order, CharSequence title)
     menu.add(0,CONTEXT_MENU1_ID,0,"トースト表示(アイテム名)");
     menu.add(0,CONTEXT_MENU2_ID,0,"トースト表示(アイテムid)");
 }
    
     @Override
     public boolean onContextItemSelected(MenuItem item) {//ContextMenuアイテム選択イベント
     switch (item.getItemId()) {
     case CONTEXT_MENU1_ID:
      //選択されたアイテム名表示
      Toast.makeText(this, _listitem, Toast.LENGTH_SHORT).show();
    
     return true;
     case CONTEXT_MENU2_ID:
      //選択されたアイテムid表示
      Toast.makeText(this, String.valueOf(adapterInfo.id), Toast.LENGTH_SHORT).show();
    
     return true;
     default:
     return super.onContextItemSelected(item);
     }
    }
}




res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android1="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <TextView
        android1:id="@+id/textView1"
        android1:layout_width="wrap_content"
        android1:layout_height="wrap_content"
        android1:text="ListView"
        android1:textAppearance="?android:attr/textAppearanceLarge" />

    <ListView
        android1:id="@+id/listView1"
        android1:layout_width="match_parent"
        android1:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

2014年1月7日

ViewGroupとは

ViewGroup

ボタンやテキストのことをViewといい

LinearLayoutやFrameLayout等のレイアウト系のことをViewGroupといいます。

言葉の定義よりもこれで何ができるかですが

  • ActionBar.TabのFramLayoutにレイアウトをセットする際に使用する。※
  • Layoutparams(fill_parentやwrap_content)を動的に変更できる
※今回紹介します。

Fragment 画面1を選択
Fragment 画面2を選択

MainActivity.java
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.container);//
ActionBar ab = getSupportActionBar();
// アイコンを表示しない
ab.setDisplayShowHomeEnabled(false);
// SHOW_TITLEのフラグを消すことで、タイトル表示を消す
ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);//tabを利用するときの決まり文句
ab.addTab(ab
.newTab()//新規作成
.setText("画面1")//tab文字
.setTabListener(
new MainTabListener<fragment1>(this, "f1",Fragment1.class)));//読み込むclassを指定
ab.addTab(ab
.newTab()
.setText("画面2")
.setTabListener(
new MainTabListener<fragment2>(this, "f2",Fragment2.class)));
ab.addTab(ab
.newTab()
.setText("画面3")
.setTabListener(
new MainTabListener<fragment3>(this, "f3",Fragment3.class)));

ab.getTabAt(1).select(); // 左:0 中:1 右:2 今回は初期tab選択位置を真ん中に指定

}
public class MainTabListener<t extends="" fragment=""> implements TabListener {

private Fragment fragment;
private final Activity activity;
private final String tag;
private final Class<t> cls;

public MainTabListener(Activity activity, String tag, Class<t> cls) {
this.activity = activity;
this.tag = tag;
this.cls = cls;
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (fragment == null) {
fragment = Fragment.instantiate(activity, cls.getName());
ft.replace(R.id.container, fragment, tag);

} else {
fragment = Fragment.instantiate(activity, cls.getName());
ft.replace(R.id.container, fragment, tag);
}
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (fragment != null) {
ft.detach(fragment);
   }
  }
 }
}

Fragment1.java (Fragment2、3はほぼ同じ内容なので省きます)
public class Fragment1  extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag1, container, false);//レイアウトxmlファイルを指定
}

@Override
public void onStart() {
super.onStart();
//ここに処理内容を記載

}
}
res/layout/container.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

</FrameLayout>
res/layout/frag1.xml (Fragment2、3はほぼ同じ内容なので省きます)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="画面1"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>
res/values/styles.xml
<resources>

    <style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light">//@style/Theme.AppCompatか@style/Theme.AppCompat.Light選択必須

    </style>

    <style name="AppTheme" parent="AppBaseTheme">

    </style>

</resources>


2014年1月5日

Viewとは

View

細かいことは色々あって難しいですが、要は、TextViewやButtonのウィジェットの元となるクラスで

描画やクリックイベント(OnClickListener)処理するときに使用します。

以下ソース例ではview.getId()でクリックイベントをセットしたButtonのIdを取得しています。

Button配置
Clickイベント
















MainAcitivity.java
public class MainActivity extends Activity implements OnClickListener{

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//ボタン部品取得
Button _btn1 = (Button)findViewById(R.id.button1);
Button _btn2 = (Button)findViewById(R.id.button2);
Button _btn3 = (Button)findViewById(R.id.button3);

//ボタンをクリックリスナーへ登録
_btn1.setOnClickListener(this);
_btn2.setOnClickListener(this);
_btn3.setOnClickListener(this);
}

@Override
public void onClick(View arg0) {
// TODO 自動生成されたメソッド・スタブ
//オススメはswitchを使用
switch(arg0.getId()){

case R.id.button1:
//【おはようボタン】のイベントを記載
Toast.makeText(this, "おはよう!", Toast.LENGTH_SHORT).show();   
break;

case R.id.button2:
//【こんにちわボタン】のイベントを記載
Toast.makeText(this, "こんにちわ!", Toast.LENGTH_SHORT).show();
break;

case R.id.button3:
//【こんばんわボタン】のイベントを記載
Toast.makeText(this, "こんばんわ!", Toast.LENGTH_SHORT).show();   
break;
}

}
}




res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    >
    <Button
        android:text="おはよう"
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
    <Button
        android:text="こんにちわ"
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
    <Button
        android:text="こんばんわ"
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
</LinearLayout>