Android実機にデバッグ版がインストールできない JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Invalid escape sequence at line 1

今日は表題のエラーで5時間ぐらいを費やしました…。

王大人「死亡確認!!」

さて、不思議なことが起こりまして、とあるAndroidアプリを、Release版はインストールできるんですが、Debug版が実機でインストールできない。

上記のエラーが出るんですよね。

最初は、google-services.json関係のエラーかと思って、その辺をFirebaseからダウンロードしたりしてましたが、直りませんでした。

結局、ほかのアプリで実績のある、gradleのバージョンとgoogle-servicesのバージョンの組み合わせで試したところ、無事に解決…。

buildscript {
repositories {
jcenter()
google()
}
dependencies {

classpath 'com.android.tools.build:gradle:3.2.1' //これ
classpath 'com.google.gms:google-services:3.2.0' // これ

}
}
 


Vue.jsを使って、facebookの通知エリアみたいなものを作るサンプルコード

「facebookの通知エリアみたいなもの」と言われても漠然としていると思いますが表示でいうと次のようなものです。

文章で要件を書くと次の通りです。

  • アイコンの右肩or左肩に未読件数のバッジが付いている
  • アイコンにマウスオーバーで下にプルダウンで表示される
  • メッセージ内容は動的に変更できる
  • 一件一件選んで消せる
  • 消したものは、既読フラグをつけて、もう未読エリアに表示しない
  • 重要なメッセージは色を変更するなどでわかりやすくする

私の javascript に関する能力としては、Web関係の仕事を5.6年前までは結構一生懸命やっていたけれども、javascriptは結局必要に迫られたときにjQueryとか jQuery UIとかでなんとかしていて、そんなに深くはやっていない、という感じのスキルです。

今回は、ちょっと急ぎで上記のものを作らないといけなくって、

「はは!この秀吉が、一夜で城を建ててみまする!」

という感じで、サクッとやる感じでやりました。結局4日間ぐらいはかかりましたので、4日城ですね。

使っているのは

  • Vue.js
  • Vuetify.js(バッジのデザインをこれにしたかった)
  • Semantic UI (メッセージのデザインをこれにしたかった)
  • axios(閉じるボタンをクリックした時に何か実行するため)

びみょいところもありますが、載せちゃいます。

<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css"
	rel="stylesheet">
<link rel="stylesheet"
	href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">

</head>
<body>
	<br>
	<div id="app">
		<div class="ui button"
			style="background-color: #ffffff; margin-left: 100px;">
			<!-- メールのアイコン -->
			<v-app style="height:50px; background-color:#ffffff;"> 
				<v-layout /> 
					<a>
						<v-badge color="red"  left> 
							<template v-slot:badge> 
								<span v-if="messages > 0">{{ messages }}</span>
							</template> 
							<bell v-on:showmenu="showMenuBelowBell()"
							v-on:hidemenu="hideMenuBelowBell()">
							</bell>
						</v-badge>					
					</a>
				</v-layout>
			</v-app>

			<!-- 通知 -->
			<notification v-for="post in posts" v-bind:key="post.id"
				v-bind:title="post.title" v-bind:content="post.content"
				v-bind:type="post.type" v-if="show_messages"></notification>
		</div>
	</div>

	<!-- 通知部分のテンプレート -->
	<script type="text/x-template" id="notification-component">
	  <div class="ui message" :class="type" v-if="!hidden" style="width:300px; text-align:left">	  
		<i class="close icon" @click="hide"></i>
		<div class="header">{{ title }}</div>
		<slot></slot>
		<div v-html="content"></div>
   	  </div>
	</script>

	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
	<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	<script>

	  Vue.component('bell', ({
			  template: '<span><i class="bell icon" v-on:mouseover="mouseover" ></i></span>',
	     	  methods: {
	  		    mouseover: function(){
	  		      console.log("マウスオーバーだよ");
		  		  this.$emit('showmenu') 
	  		    },
	
	  		    mouseleave:function(){
	  			  console.log("マウスリーブだよ");
	  			  this.$emit('hidemenu')
	  			},
	  		  }
		  	      
		}))	
			
  
	  Vue.component('notification', {
		  props: {
			  		title:{}, 
			  	  	content:{},
			        type: {
			            type: String,
			            default: 'info'
			         },
			        header: {
			       }
		  },
	      data() {
		        return {
		          hidden: false,
		   		 
		        }
		  },
	      methods: {
	          hide() {
	            this.hidden = true
	            axios.get(`https://api.github.com/users/AkikoGoto`)
	            .then(response => {
	              console.log(response.data)
	            })
	          },
	
	      },
		  template: '#notification-component'
		})	
		
		
		
	    
	  new Vue({
		  el: '#app',
		  vuetify: new Vuetify(),
		  data () {
		    return {
		     // show: false,
	
	 	      posts: [
	  		      { id: 1, title: 'せやかて' , content:'工藤', type:'info'},
	  		      { id: 2, title: 'なんだと' , content:'服部!本当なのか?', type:'error'},
	  		      { id: 3, title: 'お知らせ' , content:'ついに黒の組織のボスが判明'}
	  		    ],
	
	  		 messages: 3,
	  		 show_messages:false,
	
		    }
		  },
	
		  methods: {
	
			  showMenuBelowBell: function () {
			      this.show_messages = true
	
			    },
	
			  hideMenuBelowBell: function () {
				  this.show_messages = false
	
			    }		    		    
			    
			  }
	
		})
	
  </script>
</body>
</html>

一応、これを張り付けてhtmlファイルとしてブラウザで開けば、一番最初の画像のような挙動になるはずです。

注意点は次の通り。

  • データはVueを生成しているところ(new Vueの箇所)のpostsというところに入っています。JSONだとかなんらかの形で、ここが動的に変わるようにしてください。
  • バッジの件数は、その下のmessagesというオブジェクトになります。すみませんが、上記のpostsを自動的にカウントして入れるようになっていませんので、ここも別途やってくださいませ。
  • 閉じる×ボタンをクリックした時の挙動は、私のGithubにつながって応答が返ってきてconsoleに出力されるようになってます…。もちろん、ここも皆様がカスタマイズされると思いますので、ただのサンプルです。
  • プルダウンメニューが表示されるところはやってありますが、全体的に隠す処理はしていません。そちらもご自由に…。

Android エミュレーターで通信速度の遅い端末を作る Android Studio3.3.2

次の手順で行います。

Tools→

AVD Manager→

各エミュレーターの一覧出てくると思いますが、その鉛筆みたいなアイコンをクリック→

「Show Advanced Settings」をクリック

Netoworkという項目にSpeedとLatencyというのがありますので、それを変更。

・Fullがデフォルトで、PC上でできるかぎりのネットワーク速度を実現

・LTE なんか懐かしい  略称はLong-Term Evolution  らしい。

・HSDPA 多分、昔ハイスピードパケット通信とか言ってたあたりだと思うんですよね。この辺りから、遅さを体感できる…。

・GPRS 3Gぐらいの通信速度

下記の公式情報も参考にしてください。

https://developer.android.com/studio/run/managing-avds?utm_source=android-studio

java.lang.OutOfMemoryError: Failed to allocate a 840012 byte allocation with 555120 free bytes and 538KB until OOM

マイナーな話にはなっちゃうんですが。
AndroidのMapboxでマーカーを追加していて、タブレットで200個ぐらいマーカーを生成する画面でOOMが起こってクラッシュしてしまう、という不具合に遭遇しました。

ググると大きなBitmapをいっぱい追加するとこれが起きやすいという話です。

https://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object

Android Developersの公式でも紹介されていますね。

https://developer.android.com/topic/performance/graphics

皆さん、大体ファイルを読み込んでアプリに表示する系でこれが発生しているようですね。

私はBitmapの生成を、Mapboxのマーカーをタップした時に出るウィンドウのために作ってまして、下記のような感じになります。

public static Bitmap generate(@NonNull View view) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);

int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();

view.layout(0, 0, measuredWidth, measuredHeight);
/Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

//bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}

https://docs.mapbox.com/android/maps/examples/symbol-layer-info-window/

コード自体はMapboxの公式サンプルを利用しているだけです。

なので、上述のAndroid DevelopersやStackOverflowにあるような

BitmapFactory.Options

を使ったやり方がどうにもできませんでした…。

なので、

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);

Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.RGB_565);

に変更しました。

ARGB_8888 

にすると、1ピクセルにつき、4バイト使うらしいです。


RGB_565

にすると、1ピクセルにつき、2バイト使います。

透明部分とかが表現できませんが、しょうがない…。

ちなみに、手っ取り早くマニフェストファイルに

<application android:largeHeap=”true” > </appplication>

ってして回避することもできるようですが、これは機種によってできなかったりするらしく、また敗北感あるのでやめました…。

Tensorのshapeにクエスチョンマークが入る

PythonでKeras+TensorFlowで色々やってまして

input_tensor = Input(shape=(15, 15)) 

とやりまして、input_tensorについて調べると、

Tensor(“input_1:0”, shape=(?, 15, 15), dtype=float32)

となってます。

ふむふむ。Tensor型なのはわかった…。でもshapeにある「はてなマーク」は一体??

と疑問に思いました。

ありがたいことに、StackOverflowに答えがありました。

https://stackoverflow.com/questions/40951602/what-does-the-question-mark-in-tensorflow-shape-mean/40953146#40953146

“It means that first dimension is not fixed in the graph and it can vary between run calls”

というシンプルな答えでした。

最初の次元が決まってないので、これから追加する可能性があるから、?なんだそうです。