2013年6月26日水曜日

Buttonの背景色

Buttonの背景色

Buttonの色が背景色と混合されてしまって、不細工な色になってしまっている。

Android2.3の場合は、背景の色とButtonの画像とは別々であった。
しかし、少なくともAndroid4.2では、背景色とButtonの画像が混じり合って表示されるため、不細工になっている(主観の問題ですが)。背景色が真っ白の場合は問題は無いです。
この現象が発生するViewの構成
<LinearLayout>...上位にあるView。これに赤い色等の背景色を付ける
    <Button>...画像関係は何も操作しない。
背景の赤い色とButtonの灰色とが混じり合って、赤灰色のButtonが出来上がります。

解決策の模索
1.背景色を表示するViewとButtonとの間に、背景色が真っ白なViewを配置する。
<LinearLayout>...これに赤い色等の背景色を付ける
    <LinearLayout>...これに真っ白な背景色を付ける。
        <Button>...画像関係は何も操作しない。
しかし、LinearLayoutとButtonとは形状が異なるため、白色がハミ出てしまいます。ある種の御仁はハミ出た白色に魅力を感じるでしょう。

2.ThemeをLightにする。
res/values-v11やres/values-v14には、styles.xmlファイルがあるので、この中を次のようにする。
    <style name="AppBaseTheme" parent="android:Theme.Light">
    </style>
このようにすることで、Android2.3の場合と同じ表示になります。
Holoというのが新しいデザインです。Lightは昔のです。何か時代の波に残された感じがしますが、昔の方が良かったなとも感じます。

3.ボタンをShapeDrawableで描画する
これはまだ実施していないので、問題解決になるかどうかは知りません。

参考にしたサイトを掲示しておきます。

余談
画像処理においてsetBackgroundという名前が用いられているが、この言葉使いは誤解を生じる。私はズ~っとforegroundという画像処理の何かが存在するものだと思い込んでいたのだ(アホ)。なので、背景の画像と混じり合わないようにするため、setBackgroundColor()の引数にアルファ値を0xffにした値を代入したりしていた。そんなことをした結果、Buttonが真っ白や真っ黒になってしまい、ボタンの画像が消失した意味が分からなかった。ボタンの画像は、foregroundに描かれているに違いないという思い込みがあったのだ。(そんな思い込みをするのはアンタだけや!)
テキストはsetText()で処理をするのであるから、テキストがforegroundである訳はない。もし、テキストがforegroundであるならば、setTextという名前を用いずに、setForeground(String text)という名前にすべきだ。
反意語に相当するものが存在しないのに、一方の反意語だけを使って表現するのはやめて欲しい。
正確に表現しようとするならば、setGraphicなのではないかと思う。

余談に対するツッコミ
Buttonの内部にはViewとTextViewがあって、backgroundはViewに存在します。TextViewにはdrawable top, drawable left等が存在します。
たぶん、Viewが基底部分にあって、その画像であるため、backgroundという用語を使用しているのだろうと思います。

ちなみに、SeekBarは、ViewとProgressBarから構成されています。Viewにおけるbackgroundで何か画像を設定して、ProgressBarにおけるdrawableで何か画像を設定した場合、Viewの画像が背景に見えて、ProgressBarにおける画像が手前に見えるようになります。

2013年6月11日火曜日

ClassCastException android.widget.* cannot be cast to android.widget.*

ClassCastException android.widget.* cannot be cast to android.widget.*

下記のエラーが出た。
具体例1.java.lang.ClassCastException: android.widget.ImageView cannot be cast to android.widget.Button

具体例2.java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.Button

私が遭遇した上記エラーのViewの階層構造の概念図は次のとおりである。
<LinearLayout> parent
    <LinearLayout> child
        <Button> has it's original ID.

<LinearLayout> parentの場所から、ButtonのIDをfindViewById()を使って指定して、そのButtonを使うことはできるし、エラーは発生しなかった。アプリに1個しか存在しないIDの値を使うのであるから問題はない。

この方法で以前は問題なく動作していたが、原因は不明であるが、ある時点以降、ButtonのIDを指定すると、「それはImageViewなのでButtonにcastすることはできない」という趣旨のエラーが出て、アプリがクラッシュするようになった。エラー発生箇所によっては、ImageViewではなく、LinearLayoutであったりTextViewであったりした。XMLやIDを調べたが、ButtonはButtonであった。しかしながら、ImageViewであるとされるIDの値は、ButtonのIDの値と同一なのである。このImageViewは私には身に覚えのないViewだ。変だね。

そこで、日本人が得意とするゲーム感覚で、<LinearLayout> childの場所から、つまり、Buttonの直接上のViewから、ButtonのIDを指定して使ったところ、問題無く動作するようになった。
非論理的不都合には、非論理的対応をするのが良いのかもしれない。むむむ!

なお、<LinearLayout> childでは、addView()やremoveAllViews()を使って、その内部にViewを実行時に加えたり削除したりしていた。

leaked ServiceConnection

Activity <App Name> has leaked ServiceConnection <ServiceConnection Name>@ that was originally bound here

このエラーに関しては次のサイトで議論されている。

実行順序は次のとおりである。
  1. onDestroy()....前のActivityが実行したonDestroy()
  2. unbindService()
  3. 上記エラーログ
  4. onUnbind()....Service
  5. onDestroy()....Service
  6. onCreate()....次のActivityが実行したonCreate()
現象の原因は、Answersの<4>が参考になりそうである。
対策としてはAnswersの<3>と<8>に書かれてあるが、この対策が真実であるのか私は疑問に感じた。ので、他の方法を模索した。が、成功しなかった。
結局、対策は、Answersの<3>と<8>に書かれてあるように、unbindService()をonDestroy()で行っているのであれば、そのbindService()はonCreate()で行わねばならない、ということであった。
このような対応策が非論理的であると感じてしまうのは、果たして私だけだろうか。。。。(あんた、だけや!)。。。むむむ!

2013年6月10日月曜日

Adding Recent Query Suggestions

Adding Recent Query Suggestions

前回の記事Action Barに検索Viewを設けるでは、入力欄を設けただけだった。ここで作業を終わってしまうのであれば、単なる、マニアである。SearchManagerはSuggestionsを利用してこそ有益になる。

Adding Recent Query Suggestionsに書かれているとおり下記のとおりサンプルプログラムを作ってみた。この記事で実現されるのは、利用者が過去に入力した文字列をそのまま候補として掲示することである。

public class MainActivity extends Activity{
    private final String TAG = "MainActivity";

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.main, menu);
        SearchView sV;
        SearchManager sM = (SearchManager)getSystemService(Context.SEARCH_SERVICE);
        ComponentName c = getComponentName();
        SearchableInfo si = sM.getSearchableInfo(c);
        MenuItem mi = menu.findItem(R.id.action_Search);
        sV = (SearchView)mi.getActionView();
        sV.setSearchableInfo(si);
        sV.setIconifiedByDefault(false);
     
        /*
         * setSubmitButtonEnabled()について
         * trueは、送信ボタンが右端に表示される。
         * falseは、表示されない。
         */
        sV.setSubmitButtonEnabled(true);
     
        /*
         * setMaxWidth()について
         * これを設定しない場合、幅が狭い。このため設定した方が良い。
         * 引数には、物理画面の横幅の大きさを超える値を設定しても問題は無い。
         * 超えた値であっても、送信ボタンやアイコンは表示される。タイトル文字列は見えない。
         */
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        sV.setMaxWidth(metrics.widthPixels);
//        setTitle("");これは不要です。
        return true;
    }

    @Override
    protected void onNewIntent(Intent intent){
        setIntent(intent);
        if(Intent.ACTION_SEARCH.equals(intent.getAction())==true){
            String q = intent.getStringExtra(SearchManager.QUERY);
            SearchRecentSuggestions srs;
            srs = new SearchRecentSuggestions(this,
                MySuggestionProvider.AUTHORITY,
                MySuggestionProvider.MODE
                );
            srs.saveRecentQuery(q, null);
            Log.d(TAG, "onNewIntent() : query==" + q);
        }
    }
}

MySuggestionProvider.java
public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
    public final static String AUTHORITY = "com.example.searchable.MySuggestionProvider";
    public final static int MODE = DATABASE_MODE_QUERIES;

    public MySuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }
}


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.searchable"
    android:versionCode="1"
    android:versionName="1.0"
    >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17"
        >
    </uses-sdk>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        >
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable"
                />
        </activity>
        <provider
            android:name=".MySuggestionProvider"
            android:authorities="com.example.searchable.MySuggestionProvider"
            >
        </provider>
    </application>
</manifest>


res/xml/searchable.xml
<?xml version="1.0" encoding="utf-8"?>
<searchable
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/SearchHint"
    android:searchSuggestAuthority="com.example.searchable.MySuggestionProvider"
    android:searchSuggestSelection=" ?"
    >
</searchable>

2013年6月7日金曜日

実験:Locale.getDefault()で得られる情報

実験:Locale.getDefault()で得られる情報

本体設定で端末の言語を変更できる。
言語を変更した後、Locale.getDefault()でLocale情報を取得した場合、言語は当然変わるだろうが、国情報はどうなるのか。

結論:国情報も変わる。

本体設定で言語をEnglishに変更した後、Locale.getDefault()でLocaleを取得し、これでgetCountry()を実行させると、USが返る。

本体設定では「Language」だけを変更するような表記になっているのに、国情報も変わってしまうのだね。むむむ。

ちなみに、getResources().getConfiguration().localeも同様の結果になった。

「オレは英語を話すんだけど、住所地と国籍は日本なんだ」という御仁への配慮は、(以下省略)