2021年1月9日土曜日

[Other]コードのシンタックスハイライト

コードをハイライトするために、SyntaxHighlighterを使っていたんですがリンク切れで遅くなていました。
で、とりあえずスタイルやJSのリンクを消したものの、コードのサンプル表示がかっこ悪かったので、これを機に修正しました。
で、使ったのが、「highlight.js」です。
SyntaxHighlighterとくらべ軽量で言語の対応も多いらしいです。 ということで使い方。
↓のコードを<head>に埋め込めばOK
<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
サポートしている言語は、GitHubのほうを参照で。
使い方はhttps://highlightjs.org/usage/を参照。


当サイトは、VisualSutudio風のデザインを使っていますが、このデザイン枠がなんです。
ということで、スタイルの一部を改変。現状はこのスタイル(.hljs)が必ずセットされるので、それをチョット改変。
<style type='text/css'>
.hljs {
  display:block;
  border:1px solid #ffa500;
}
</style>

デモサイトがあり、こっちも便利。分かりやすい。参考になる。


取り合えず、チョットやな感じで何とかしたいこと。
  • 1行目の空行<pre><code>の後ろに改行入れると、改行されちゃう
  • <と>。コードをそのまま貼り付けれない。1行に1個までなら何とかなるっぽいけど、理由がわからない。js内に変換してそうなコードはあるんだけど。。。うまく動いていないのだろうか
・・・こいつら何とかしたい。

2021年1月6日水曜日

[Android]非推奨になったAsyncTaskの代わりに、ExecutorServiceとLiveDataを使う

Android11(APIレベル30)がリリースされてからしばらくたちます。
その中でも困りそうなのが、AsyncTaskが非推奨になったことです。
AsyncTaskを使うと、AndroidStudioに取り消し線がつくのが気に入らないので、今のうちにイイ感じの実装方法を覚えていおたほうがいいかな。と思います。

AsyncTaskを機能分割すると、流れ的に大きく3つ。
  1. doInBackground(Params... params) バックグラウンド処理
  2. onProgressUpdate(Progress... values) 進捗状況をUIで表現
  3. onPostExecute(Result result) 1.の結果を処理する(成功したらDBに登録とか)
このうち、1,3は必須。2は場合によってって感じかな。と思います。

で、よさげな実装案は、次の通り。
  1. java.util.concurrent.ExecutorServiceでバックグラウンド処理
  2. JetPackのLiveDataで進捗状況をUIで表現
  3. JetPackのLiveDataで1.の結果を処理する
1,3はイイ感じかなと思います。2はちょっとダサいけどできなくはない。じゃあ実際にどうするか。というと、
  1. JetPack LiveDataの利用準備
  2. LiveData用モデルの作成
  3. LiveDataの更新コールバックを受け取るリスナーの設定
  4. ExecutorServiceを使った非同期処理の実行
という感じかな。と思います。じゃあ、実装例。

1.JetPack LiveDataの利用準備
app/build.gradleに以下追記。ADDってなっている部分。
dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.navigation:navigation-fragment:2.2.2'
    implementation 'androidx.navigation:navigation-ui:2.2.2'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    //<<ADD
    def lifecycle_version = "2.2.0"
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
    annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
   //>>ADD
}
2.LiveData用モデルの作成(クラスの用意) 
↓のような感じのクラスを作る。
public class MyViewModel extends ViewModel {
    private MutableLiveData<String> currentName = new MutableLiveData<String>();
    public MutableLiveData<String> getCurrentValue() {
        return currentName;
    }
}
3.LiveDataの更新コールバックを受け取るリスナーの設定
4.ExecutorServiceを使った非同期処理の実行
public class FirstFragment extends Fragment {

    //2.LiveData用モデルの作成(変数定義)
    private MyViewModel model;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //2.LiveData用モデルの作成(インスタンス生成)
        model = new ViewModelProvider(this).get(MyViewModel.class);

        //3.LiveDataの更新コールバックを受け取るリスナーの設定
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newValue) {
                // 画面の更新
                TextView textView = view.findViewById(R.id.textview);
                textView.setText(newValue);
            }
        };
        model.getCurrentValue().observe(this, nameObserver);

        view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //4.ExecutorServiceを使った非同期処理の実行
                ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(new Runnable() {
                    @Override
                    public void run() {
                        //10秒経過後、ワーカースレッドより、モデルの値を更新
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                        }
                        String anotherName = "3秒経過 " + new Date();
                        //他のスレッドから情報更新する場合、postValueで値をセットする必要がある
                        model.getCurrentValue().postValue(anotherName);
                    }
                });
            }
        });
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_first, container, false);
    }

}

LiveDataを使うことでObserverパターンを実現しています。
また、postValueを使うことで、スレッドを意識する必要がなくなります。
Handlerを使えば、同じことはできますが、スレッドの入れ替えを隠蔽することで、コードがわかりやすくなりますね(個人的な感覚)。
また、値の取り回しが複数になる場合、面倒なので、更新通知用のフィールドを設けるのもありかなと思います。

「2.JetPackのLiveDataを使う」は、ちょっとダサいですけど、MyViewModelに進捗状況を表す数字を持たせ、postValueすればできるかな。と思います。
・・・でもダサいですね。

2021年1月3日日曜日

[PHP]Windows × xampp × Visual Studio CodeでPHPをデバッグ(Step実行)する

どのプログラム言語でも、デバッグするには変数など内部データを見る必要があります。
変数を簡単に見るには、ステップ実行するのが一番の近道かなと思います。

今回、PHPの開発に携わる機会があり、xampp環境でステップ実行するための環境を作ったんですが、うまくいかない。。。。
何がうまくいかないか。というと「ブレークポイントを設定しても止まらない」です。


環境は、以下の通りです。
 ・PHP Version 8.0.0
 ・Xdebug 3.0.1
 ・Visual Studio Code 1.52.1
 ・PHP Debug 1.14.5(Visual Studio Code のデバッグ用プラグイン)

環境により違いはあると思いますが、この環境においての原因は以下の2点でした。
 ・Xdebug v3.0.0系より、php.iniに書く設定が変わった
 ・デバッグ用のポート番号が変わった

対策は以下の2つ。
 1.PHP.iniの設定
 2.lunch.jsonの設定


1.PHP.iniの設定
[XDebug]
xdebug.mode=debug
xdebug.start_with_request=yes
zend_extension = C:\xampp\php\ext\php_xdebug-3.0.1-8.0-vs16-x86_64.dll
うまくいっている場合、↓のURLで確認ができる。
http://localhost/dashboard/phpinfo.php
xdebugの「Step Debugger」が「enabled」になっていたらOK。

zend_extensionはバージョンによって異なる。コイツの導き出し方は、他のサイトを探してみてください。


2.lunch.jsonの設定
ポート番号が変わったらしい。その設定を合わせる。 9001→9003

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    'version': '0.2.0',
    'configurations': [
    
        {
            'name': 'Listen for XDebug',
            'type': 'php',
            'request': 'launch',
            'port': 9003,
            'runtimeExecutable': 'C:\\xampp\\php\\php.exe'
        },
        {
            'name': 'Launch currently open script',
            'type': 'php',
            'request': 'launch',
            'stopOnEntry': true,
            'program': '${file}',
            'cwd': '${fileDirname}',
            'port': 9003,
            'runtimeExecutable': 'C:\\xampp\\php\\php.exe'
        }
    ]
}
設定の変更は、Visual Studio Codeのメニュー「実行(R)」→「構成を開く」で編集できます。

Lunch Currently open Scriptを選択し、F5でデバッグスタート。
ブレークポイントを設定しておくと、そこで止まるようになりました。