2016年3月9日水曜日

BroadcastReceiverでIntent.ACTION_PACKAGE_REPLACEDを受け取る

BroadcastReceiverでIntent.ACTION_PACKAGE_REPLACEDを受け取る

アプリの改版を行った場合、アプリは、BroadcastReceiverでandroid.intent.action.PACKAGE_REPLACEDを受け取ります。
このPACKAGE_REPLACEDに基づき実行されるコードは、旧版でしょうか、それとも新版でしょうか。

解答は、新版です。

何の根拠も無く、間違った方で、自分勝手に思い込みをしてしまわないようにしましょう。

2016年2月29日月曜日

PreferenceFragmentを使って複雑なViewGroupを表示・操作したい場合

PreferenceFragmentを使って複雑なViewGroupを表示・操作したい場合

表示する画面のxml:preference_version.xml
<?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="wrap_content"
    android:orientation="vertical"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:autoLink="web"
        android:text="@string/test"
        >
    </TextView>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:paddingTop="20dp"
            android:text="@string/app_name"
            >
        </TextView>
        <TextView
            android:id="@+id/TextView_Preference_Version"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:paddingTop="20dp"
            >
        </TextView>
    </RelativeLayout>
</LinearLayout>

\res\xml\preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <PackageName.VersionPreference
        android:key="PreferenceScreen_Version"
        android:layout="@layout/preference_version"ここがポイント
widgetLayoutを使うと適切に表示されない。
        >
    </PackageName.VersionPreference>
</PreferenceScreen>

PackageName.VersionPreference.java
public class VersionPreference extends Preference{
    private Context con;
    public VersionPreference(Context context){
        super(context);
        con = context;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public VersionPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        con = context;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public VersionPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        con = context;
    }

    public VersionPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        con = context;
    }

    @Override
    protected void onBindView(View view){
        super.onBindView(view);
        LinearLayout llParent = (LinearLayout) view;
        TextView tv = (TextView) llParent.findViewById(R.id.TextView_Preference_Version);
        PackageInfo pi;
        try{
            pi = con.getPackageManager().getPackageInfo(
                    con.getPackageName(),
                    PackageManager.GET_ACTIVITIES
            );
            Resources r = con.getResources();
            String s = r.getString(R.string.Version) + pi.versionName;
            tv.setText(s);
        }
        catch(PackageManager.NameNotFoundException e){
        }
    }
}

ListPreferenceを使って、longのデータを保存・読込を行う

ListPreferenceを使って、longのデータを保存・読込を行う

ListPreferenceをそのまま使うと、保存・読込のデータはStringになる。
これは不便だ。そこで、longによりデータの保存・読込を行う。

public class myLP extends ListPreference{
    public myLP(Context context){
        super(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public myLP(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public myLP(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public myLP(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue){
        if(restoreValue){//long型データをファイルから読む。
            long lValue;
            String s;
            lValue = //PreferenceManager.getDefaultSharedPreferences()を使ってデータを読む。
            s = String.valueOf(lValue);
            setValue(s);
        }
        else{//ファイルへ保存する。
            //このファイルへ保存する部分は、別途本体において、自分でプログラムする。
        }
    }
}

class SettingsFragment extends PreferenceFragmentにて
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue){
        String sValue = (String)newValue;
        //Long.parseLong(sValue)を
        //PreferenceManager.getDefaultSharedPreferences()を使って保存する
        return true;
    }

(参考)

2016年2月6日土曜日

PreferenceFragmentの評価


PreferenceFragmentの評価
Preference情報を基調としているPreferenceFragmentの評価はどうなのだろうか。
CheckBoxPreference等ごく限られた道具しかない。データの出し入れに特化したものだ。画面表示関係には弱い。
例えば、PreferenceScreenにButtonを配置したい場合、どうするのか。

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        Preference preferenceButton = findPreference("PreferenceScreen_btnClose");
        preferenceButton.setLayoutResource(R.layout.preference_button);
        preferenceButton.setOnPreferenceClickListener(this);
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public boolean onPreferenceClick(Preference preference){
        if(preference==findPreference("PreferenceScreen_btnClose")){
            //ここでButton押し下げ関係処理をする
            return true;
        }
        return false;
    }

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <Preference
        android:key="PreferenceScreen_btnClose"
        >
    </Preference>
</PreferenceScreen>

R.layout.preference_button
<?xml version="1.0" encoding="utf-8"?>
<Button
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:text="@string/aaaa"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="false"(必要)
    android:focusable="false"(必要)
    android:drawableStart="@android:drawable/ic_menu_close_clear_cancel"
    >
</Button>

単純にクリックするだけであれば悩まない。
複雑なViewGroupを表示・操作したい場合どうするのか。
Preferenceを拡張して行うということである。職人技ですね。普通のプログラマーが自力だけでこのコードを書けるとは思えない。
「複雑な形状のViewの表示は別途画面を設けてください」というのが、本システム設計者の考え方かもしれない。



SharedPreferences

SharedPreferences

SharedPreferencesを用いてデータを保存する方法は2通りある。

その1.
Context.getSharedPreferences("thisName", Context.MODE_PRIVATE)を使う方法
簡単なサンプルは次のとおりです。
boolean b;
SharedPreferences sp;
sp = con.getSharedPreferences("thisName", Context.MODE_PRIVATE);
b = sp.getBoolean("thisKey", false);

その2.
PreferenceManager.getDefaultSharedPreferences()を使う方法
データを簡単に保存する方法(Preference編)

両者の違いは次のサイトに解説されている。
Difference between getDefaultSharedPreferences and getSharedPreferences
保存する名前(保存先)が異なるとのことである。機能に違いは無い。各々独立したデータとして取り扱うことになる。

仕掛け
Preferencesによるデータはファイルに保存される。
このファイル名は、Context.getSharedPreferences()であれば、その第一引数に指定した文字列になる。
PreferenceManager.getDefaultSharedPreferences()の場合は、context.getPackageName() + "_preferences"という、固定された名前(プログラマーが指定できない名前)になる。

このような名前を持つファイルの中に、任意の個数の、任意の名前のKeyが存在することになる。各々のKeyには、1個の何らかの値がくっついている。
Keyを指定することにより、値を操作することができる。

保存先がファイルであるから、複数設けるとアクセスに時間がかかるかもしれない。ファイルは1個にまとめれば効率的かもしれない。

PreferenceFragmentで使いたい場合
既にContext.getSharedPreferences()を用いてアプリを運用してしまっている場合であって、これをPreferenceFragmentで使用したい場合、取り扱うデータをContext.getSharedPreferences()で保存・読込ができるようにしなければならない。
\res\xml\preferences.xml
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <CheckBoxPreference
        android:key="ここにContext.getSharedPreferences()で使っているKeyを設定する"
        android:title="...."
        android:summary="...."
        >
    </CheckBoxPreference>
</PreferenceScreen>

PreferenceFragment.java
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        PreferenceManager pm;
        cbQuit = (CheckBoxPreference)findPreference("キー");
        pm = cbQuit.getPreferenceManager();
        pm.setSharedPreferencesName("名前");//取り扱うファイル名を変更する。
        boolean "値" = "変更後のファイルのキーから値を取得する"
        cbQuit.setChecked("値");

チェックボックスが1個だけなら良いが、2個以上の場合、onPreferenceChange()においてしっかりと値を保存しておかねばならない(意味不明)。
        pbQuit.setOnPreferenceChangeListener(this);
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue){
        if(preference==cbQuit){
            boolean b = (boolean)newValue;
            (ここで値を保存しておく)
            return true;
        }
        return false;
    }


2016年1月22日金曜日

MountService No primary storage defined yet hacking together a stub

MountService No primary storage defined yet hacking together a stub

Android 6.0のエミュレータで上記のエラーが発生します。
これが原因で他のアプリが動かなくなります。
解決方法は、このエラーが発生するエミュレータを捨てて、Android Virtual Device Managerで新規にエミュレータを作成してください。残念です。

2015年12月6日日曜日

Windows 10 KB3116908 0x80070570

Windows 10 KB3116908 0x80070570

これは、パソコンのWindows 10 のシステム更新に関する情報です。

x64 ベース システム用 Windows 10 バージョン 1511 の累積的な更新プログラム (KB3116908)
に関する更新をしようとすると、
エラーコード:(0x80070570)
が発生します。これに関する回答は次のサイトにあります。
Error code: (0x80070570) - When trying to download Win10 pro cumulative (KB3116908)

パソコンの"C:\Windows\SoftwareDistribution\Download"にあるフォルダーやファイルを全て削除すれば、上記エラーは無くなり、更新ができます。