eclipseでサーブレットを「サーバーで実行」するとき、サーバーを再起動するか尋ねるダイアログが出て欲しいのに出てきてくれないときの対処をメモ。
[Windows: ウインドウ/ Mac: Eclipse] → [設定] → [サーバー] → [起動] → [必要な場合はサーバーの再起動]
ダイアログが出てきてくれないときはここが「なし」になっている可能性。
ソフトウェア開発に関することなど
eclipseでサーブレットを「サーバーで実行」するとき、サーバーを再起動するか尋ねるダイアログが出て欲しいのに出てきてくれないときの対処をメモ。
[Windows: ウインドウ/ Mac: Eclipse] → [設定] → [サーバー] → [起動] → [必要な場合はサーバーの再起動]
ダイアログが出てきてくれないときはここが「なし」になっている可能性。
8080ポートを使用しているPIDをそのままkillに渡しているだけです。
lsof -t -i:8080 | xargs kill -9
lsof -i:8080
→ 8080を使用しているプロセスが誰か調べる-t
→ そのPIDだけもらう
| xargs kill -9
パイプで受け取ったPIDをkill (-9:強制終了)
putStringSet()
直後にアプリを再起動すると、getStringSet()
の結果が空要素になる。(ならないときもある)
getStringSet()
で受け取ったSet<String>
に対して要素の操作をしない。
getStringSet()
で受け取ったSet<String>
に要素を追加して、それをそのままputStringSet()
する。
val set = sharedPreferences.getStringSet("hogehoge", mutableSetOf()) set.add("fugafuga") sharedPreferences.edit().putStringSet("hogehoge", set).commit()
// setの要素数が0 val set = sharedPreferences.getStringSet("hogehoge", mutableSetOf())
getStringSet()
で受け取ったSet<String>
を直接触らず、toMutableSet()
で別Setを作ってそれを操作&putStringSet()
する。
val set = sharedPreferences.getStringSet("hogehoge", mutableSetOf()).toMutableSet() set.add("fugafuga") sharedPreferences.edit().putStringSet("hogehoge", set).commit()
getStringSet()
で取得したSetの要素を操作しないようにとのこと。データの整合性(一貫性)はそもそも保証されない。
Note that you must not modify the set instance returned by this call. The consistency of the stored data is not guaranteed if you do, nor is your ability to modify the instance at all.
SharedPreferences | Android Developer
久々にKotlinでokhttp3を使ったらいきなり落ちたのでメモ。
Rejecting re-init on previously-failed class java.lang.Class: java.lang.NoClassDefFoundError: Failed resolution of: Lorg/conscrypt/ConscryptHostnameVerifier;
val client = OkHttpClient() // ここで落ちる val request = Request.Builder() .url("https://...") .build() client.newCall(request).enqueue(object : okhttp3.Callback { @Throws(IOException::class) override fun onResponse(call: Call, response: Response) { // ..... } override fun onFailure(call: Call, arg1: IOException) { // .... } })
okhttp自体のバージョンを下げることで一旦対応。
dependencies { // .... // implementation 'com.squareup.okhttp3:okhttp:4.4.0' implementation 'com.squareup.okhttp3:okhttp:4.0.0' }
org.conscrypt:conscrypt-android
をimplementationするようにという文献もありましたが、本来conscryptはokhttp3にとってoptionでありokhttp側のバグと考えられるので一旦この方法で様子を見ることに。
OkHttp 4.3.1 spams log, didn’t find class “org.conscrypt.ConscryptHostnameVerifier” on path #5760
2020/05/28 更新:BugのLabelがついている。まだOpen。
2020/10/14 更新:4.8で解決しそうということでcloseされている。
Macだとアクティビティモニタで簡単にプロセスをkillできますが(自分はそうしてた)、Windowsはnetstatしたりサービス一覧を調べたりする方法が出てきて、なんか大変そうだったので。
PowerShellでこのスクリプトを実行します。
$processes = Get-Process -Id (Get-NetTCPConnection -LocalPort 8080,8005,8009).OwningProcess foreach($process in $processes) { Stop-Process $process.Id }
powershell
とか打つと候補に出てくるエラーっぽい赤い文字が出るかもしれませんが、8005やか8009番ポートを使用しているアプリケーションが存在していないだけで特に問題ありません。
8080, 8005, 8009番ポートを使用しているプロセスを一括で終了しています。
8080番ポートを使うサーバーを起動したいけど、8080番ポートを使用している先客(プロセス)がすでに実行中なので、起動できない。
(すでに実行中のそれは、大抵はeclipseで自分が起動したプロセスの残骸だったりする)
eclipseでtomcatのポート番号を変更する方法もありますが、このエラーは前述の通りプロセスの残骸が原因なので、そのプロセスを終了させるほうが正攻法と思われます。(最終手段のPC再起動も事実上はその残骸プロセスを終了させる方法)
プレビューしているSurfaceViewがタップされた座標に応じてフォーカス固定したかったけども、まとまった情報がなかったので個人的なメモ。
例外のハンドリングやCameraCaptureSessionのnullチェックなどは割愛しているので注意。
// Activityの中 private var cameraDevice: CameraDevice? = null private var cameraSession: CameraCaptureSession? = null private var previewRequestBuilder: CaptureRequest.Builder? = null
// Activityの中 private var cameraDevice: CameraDevice? = null private var cameraSession: CameraCaptureSession? = null private var previewRequestBuilder: CaptureRequest.Builder? = null // 前提: // ActivityCompat.requestPermissionsで、カメラ使用の許可をユーザから得ている // カメラがすでにオープンしている。 // onResume()とかで、上記のpreviewRequestBuilder, cameraDevice, cameraSessionにすでに参照を入れている。 // CameraCaptureSession.StateCallback#onConfiguredまで行っていて、プレビューが始まっている。 // surfaceViewはプレビュー用のView surfaceView.setOnTouchListener { _: View, motionEvent: MotionEvent -> if (motionEvent.action == MotionEvent.ACTION_DOWN) { // タップされた場所から20pxの範囲に対してフォーカスさせる // 画面のorientationに応じて別途座標の反転などが必要 val rectangle = MeteringRectangle(motionEvent.x.toInt(), motionEvent.y.toInt(), 20, 20, MeteringRectangle.METERING_WEIGHT_MAX) previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO) previewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(rectangle)) previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START) // 露出の調整やフラッシュが必要なときは適宜previewRequestBuilder#setする // builder.set(CaptureRequest.CONTROL_AE_REGIONS, arrayOf(rectangle)) // builder.set(CaptureRequest.CONTROL_AE_XXXXXXX, XXXXXXX) cameraSession!!.setRepeatingRequest(previewRequestBuilder.build(), null, null) // CallbackやHandlerを指定する場合 /* cameraSession!!.setRepeatingRequest(previewRequestBuilder.build(), object : CameraCaptureSession.CaptureCallback() { // コールバックが必要ならここに処理を記述 }, handler) */ } true }
API Level 24 (Android 7.0)で追加された、GnssStatusの取得方法をメモ。
manifest
android.permission.ACCESS_FINE_LOCATION
MainActivity
override fun onResume() { super.onResume() // LocationManagerの取得 locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager // ユーザが位置情報のアクセスを許可しているか if (ContextCompat.checkSelfPermission(this@MainActivity, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { //GnssStatusCallbackの登録 locationManager.registerGnssStatusCallback(gnssCallback) } else { // 位置情報の取得が許可されていない // TODO: requestPermissionsでユーザの許可をもらう } } private val gnssCallback: GnssStatus.Callback = object:GnssStatus.Callback(){ override fun onSatelliteStatusChanged(status: GnssStatus?) { status?.let { val satelliteCount = it.satelliteCount // ..... } } } override fun onPause() { super.onPause() gnssCallback.let { locationManager.unregisterGnssStatusCallback(it) } }
Log4j2 + サーブレット(Tomcat)でとりあえず任意のファイルとコンソールへログ出力する上で最低限すべきことをメモ。ログレベルの制御といったことまでは書いていません。
Apache ソフトウェア財団から最新版をダウンロード
ダウンロードしたzipにいっぱいjarが入っています。そのうち以下のファイルをWEB-INF/libにコピー。
大抵はコピーした段階でeclipseが自動でビルドパスに追加してくれるはずです。
※XXXの部分にはバージョン番号が入ります。
WEB-INF直下に「log4j2.xml」を以下の内容で記述しつつ、ハイライトされている部分を適宜書き換えます。
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="OFF"> <Appenders> <RollingFile name="file" fileName="C:\XXX\YYY\hogeapp.log" <!-- 書き込んでほしいログファイルの場所 --> filePattern="C:\XXX\YYY\hogeapp-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="[%date] %-5p %location %m%n"/> <Policies> <OnStartupTriggeringPolicy /> <SizeBasedTriggeringPolicy size="256 KB" /> </Policies> <DefaultRolloverStrategy max="100"/> </RollingFile> </Appenders> <Loggers> <Logger name="自分のアプリケーションのパッケージ名" level="trace"> <AppenderRef ref="file" /> </Logger> </Loggers> </Configuration>
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @WebServlet("/Main") public class Main extends HttpServlet { private static Logger logger = LogManager.getLogger(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.warn("まずい"); logger.error("かなりまずい"); } }