質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

3686閲覧

Androidアプリで端末内に保存してあるjsonファイルからデータを取得したい

adakatt12

総合スコア1

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2022/01/20 13:22

編集2022/01/21 00:41

はじめに

AndroidstudioでARアプリを開発しています。言語はjavaを使用しています。
カメラを向けた先に目的地があれば目的地の名称と現在地からの距離をの書かれた吹き出しを表示するというアプリです。

実現したいこと

目的地のデータをandroid端末の内部ストレージに保存してあるjsonファイルから取得し、後のプログラムにて使用したいです。

現状

実行時にエラーは出ないのですが、アプリを起動したときに吹き出しが表示されません。
考えられる原因は、内部ストレージからjsonファイルの取得ができていない、jsonファイルの読み取り方が間違っている、jsonから得た値の受け渡しが出来ていない、などだと思うのですが、初心者の私にはどこが問題なのか分かりませんでした。
知識のある方から見て、どこが問題であるのかご指摘頂けたら幸いです。よろしくお願いします。

sample.json

1[{ 2 "info":"ここに目的地の名称が入ります", 3 "latitude":35.xxxxxx, 4 "longitude":138.xxxxx 5 }, 6 { 7 "info":"〇〇〇〇〇〇", 8 "latitude":35.yyyyyy, 9 "longitude":138.yyyyyy 10 }, 11 ~略~ 12}] 13

/data/data/[packagename]/files/sample.json のように保存しています。

Overlayview.java

1package com.example.secondar6; 2 3import android.content.Context; 4import android.graphics.Canvas; 5import android.graphics.Color; 6import android.graphics.Paint; 7import android.graphics.Path; 8import android.graphics.RectF; 9import android.view.Display; 10import android.view.View; 11import android.view.WindowManager; 12 13import com.google.android.gms.maps.model.LatLng; 14 15import org.json.JSONArray; 16import org.json.JSONException; 17import org.json.JSONObject; 18 19import java.io.BufferedReader; 20import java.io.File; 21import java.io.FileNotFoundException; 22import java.io.FileReader; 23import java.io.IOException; 24import java.util.ArrayList; 25 26public class OverlayView extends View { 27 28 // カメラの画角を指定する 29 private final int ANGLE = 71; 30 // ARテキストの見える範囲を指定する 31 // ここでは3kmほどに指定する 32 private final float VIEW_LIMIT = 3000; 33 34 //赤道半径 35 private final double RADIUS = 6378137; 36 37 // ディスプレイサイズ 38 private int displayX; 39 // コンパスの描画位置を指定する 40 private final float POS_COMPASSX = 100; 41 private final float POS_COMPASSY = 100; 42 43 // 向きを保持する変数 44 float direction; 45 46 // 現在地を保持する変数 47 float posx; 48 float posy; 49 50 // ARテキストの情報を保持するオブジェクト 51 private ArrayList<readJson.GPSdata> glist; 52 53 public OverlayView(Context context) { 54 super(context); 55 // 画面サイズの取得 56 Display disp = ((WindowManager) context 57 .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 58 displayX = disp.getWidth(); 59 } 60 61 public static class readJson { 62 public static ArrayList<GPSdata> jlist = new ArrayList<>(); 63 public static void main(String[] args) throws JSONException { 64 String data = readFile(); 65 JSONArray jarray = new JSONArray(data); 66 67 for (int n = 0; n < jarray.length(); n++) { 68 JSONObject jobject = jarray.getJSONObject(n); 69 70 String info = (String) jobject.get("info"); 71 String slatitude = (String) jobject.get("latitude"); 72 String slongitude = (String) jobject.get("longitude"); 73 74 double latitude = Double.parseDouble(slatitude); 75 double longitude = Double.parseDouble(slongitude); 76 77 jlist.add(new GPSdata(info, latitude, longitude)); 78 } 79 } 80 81 public static class GPSdata { 82 String info; 83 double latitude; 84 double longitude; 85 86 public GPSdata(String info, double latitude, double longitude) { 87 this.info = info; 88 this.latitude = latitude; 89 this.longitude = longitude; 90 } 91 } 92 } 93 94 private static String readFile() { 95 Context context = Myapplication.getAppContext(); 96 String fileName = "sample.json"; 97 try { 98 File file = new File(context.getFilesDir(),fileName); 99 BufferedReader br = new BufferedReader(new FileReader(file)); 100 101 String data = " "; 102 String str = br.readLine(); 103 while (str != null){ 104 data += str; 105 str = br.readLine(); 106 } 107 br.close(); 108 return data; 109 }catch (FileNotFoundException e){ 110 System.out.println(e); 111 return null; 112 }catch (IOException e){ 113 System.out.println(e); 114 return null; 115 } 116 } 117 118 119 // (1)描画処理 120 @Override 121 protected void onDraw(Canvas canvas) { 122 Paint paint = new Paint(); 123 paint.setAntiAlias(true); 124 125 // 0.1秒休止 126 // 吹き出しの高速移動によるちらつきを抑える 127 try { 128 Thread.sleep(100); 129 } catch (InterruptedException e) { 130 e.printStackTrace(); 131 } 132 133 ArrayList<readJson.GPSdata> glist = readJson.jlist; 134 135 // 追記:ARテキストの描画 136 for (int i = 0; i < glist.size(); i++) { 137 // データの読み込み 138 readJson.GPSdata gdata = glist.get(i); 139 String info = gdata.info; 140 double y = gdata.latitude; 141 double x = gdata.longitude; 142 143 // ARテキストとの距離を求める 144 double dx = (x - posx); 145 double dy = (y - posy); 146 147 //緯度・経度差を距離(m)に直す 148 double yrad = Math.toRadians(y); 149 double posyrad = Math.toRadians(posy); 150 double dxrad = Math.toRadians(dx); 151 float distance = (float)(RADIUS * Math.acos(Math.sin(yrad)* Math.sin(posyrad) 152 + Math.cos(yrad) * Math.cos(posyrad) * Math.cos(dxrad))); 153 154 155 // ARテキストと現在地のなす角を求めて正規化する 156 double angle = Math.atan2(dy, dx); 157 float degree = (float) Math.toDegrees(angle); 158 degree = -degree + 90; 159 if (degree < 0) 160 degree = 360 + degree; 161 162 // 端末の向きとARテキストとの角度の差を求める 163 float sub = degree - direction; 164 if (sub < -180.0) 165 sub += 360; 166 if (sub > 180.0) 167 sub -= 360; 168 169 // ARテキストが視野に存在すれば描画処理を行う 170 if (Math.abs(sub) < (ANGLE / 2)) { 171 // 距離によってARテキストのサイズを決める 172 float textSize = 60 * (VIEW_LIMIT - distance) 173 / VIEW_LIMIT; 174 paint.setTextSize(textSize); 175 176 // ARテキストの描画を描画する 177 String infoDistance = info + " " + (int)distance + "m" ; 178 float textWidth = paint.measureText(infoDistance); 179 float diff = (sub / (ANGLE / 2)) / 2; 180 float left = (displayX / 2 + displayX * diff) - (textWidth / 2); 181 drawBalloonText(canvas, paint, infoDistance, left, 200); 182 } 183 } 184 185 // コンパスを描画する 186 drawCompass(canvas, paint); 187 } 188 189 private void drawBalloonText(Canvas canvas, Paint paint, String text, 190 float left, float top) { 191 // 文字列の幅を取得 192 float textWidth = paint.measureText(text); 193 // フォント情報の取得 194 Paint.FontMetrics fontMetrics = paint.getFontMetrics(); 195 196 // 文字列の20ポイント外側を囲む座標を求める 197 float bLeft = left - 20; 198 float bRight = left + textWidth + 20; 199 float bTop = top + fontMetrics.ascent - 20; 200 float bBottom = top + fontMetrics.descent + 20; 201 202 // 吹き出しの描画 203 RectF rectF = new RectF(bLeft, bTop, bRight, bBottom); 204 paint.setColor(Color.argb(100,0,255,0)); 205 canvas.drawRoundRect(rectF, 50, 50, paint); 206 207 208 // 三角形の描画 209 paint.setStyle(Paint.Style.FILL_AND_STROKE); 210 Path path = new Path(); 211 float center = left + textWidth / 2; 212 float triangleSize = paint.getTextSize() / 2; 213 path.moveTo(center, bBottom + triangleSize); 214 path.lineTo(center - triangleSize , bBottom ); 215 path.lineTo(center + triangleSize , bBottom ); 216 path.lineTo(center, bBottom + triangleSize); 217 canvas.drawPath(path, paint); 218 219 // 文字列の描画 220 paint.setColor(Color.WHITE); 221 canvas.drawText(text, left, top, paint); 222 223 } 224 225 // (2)コンパスの描画 226 private void drawCompass(Canvas canvas, Paint paint) { 227 Path path = new Path(); 228 path.moveTo(POS_COMPASSX, POS_COMPASSY - 40); 229 path.lineTo(POS_COMPASSX + 20, POS_COMPASSY + 20); 230 path.lineTo(POS_COMPASSX - 20, POS_COMPASSY + 20); 231 path.moveTo(POS_COMPASSX, POS_COMPASSY - 40); 232 paint.setColor(Color.RED); 233 canvas.rotate(-direction, POS_COMPASSX, POS_COMPASSY); 234 canvas.drawPath(path, paint); 235 canvas.rotate(direction, POS_COMPASSX, POS_COMPASSY); 236 } 237 238 // (3)センサー値の取得と再描画 239 public void drawScreen(float preDirection,LatLng latlng) { 240 // センサーの値から端末の向きを計算する 241 direction = (preDirection + 450) % 360; 242 // 座標情報の取得 243 if(latlng != null){ 244 posy = (float) latlng.latitude; 245 posx = (float) latlng.longitude; 246 } 247 // onDrawを呼び出して再描画 248 invalidate(); 249 } 250} 251

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/01/20 14:50

その json ファイルはアプリに組み込んで配布するものでしょうか? あと、吹き出しが出ない件は、Logcat やデバッガなどを使って、何がどこまでできてるかを確認すると良いのでは。
adakatt12

2022/01/20 15:11

jsonファイルを組み込んで配布は行わないです。 アプリケーション内でファイルをダウンロードする機能があり、そのファイルの保存先が/data/data/[packagename]/files/なのでそこからダウンロードしたjsonファイルを使用したい、といった感じです。
hoshi-takanori

2022/01/20 15:25

Json クラス (名前が微妙だし、static ってことは内部クラスかな…) に main という名前のメソッド (main って名前はどうかと思います…) は呼ばれてますか? あと、インデントや中括弧の対応が微妙だし…。
adakatt12

2022/01/20 16:25

おっしゃる通りJsonクラスは内部クラスになっています。インデントと中括弧に関してはここに書き込む際に一括でコピーペーストすれば良かったのですが部分的にコピーペーストしてしまったのでおかしくなってしまっています。すみません。 加えてメソッドの件なのですが、メソッドが呼ばれているかを確認するにはどういった手順を踏めばいいのでしょうか?勉強不足で申し訳ありません、ご教授頂けたら幸いです。
jimbe

2022/01/20 17:55

クラス名やメソッド名は既存のものと被らない・勘違いされないように命名して頂けると助かります。 特に本件のようにクラス階層が分からず import も無くコードの一部のみのご提示では、どれが既存でどれが作成中のものかの区別が付きにくく、再現テストもし難くなります。
adakatt12

2022/01/21 00:42

ご指摘いただきありがとうございます。import文を含めたコード全体を掲載しました。ご覧いただけたら幸いです。
Wind

2022/01/21 01:08

カメラとかセンサーとか画像処理は今回の質問に不要なので、/data/data/[packagename]/files/sample.jsonを読むだけのシンプルなソースコードを作成してみてください。 どこに問題があるか、切り分ける必要があります。
hoshi-takanori

2022/01/21 01:43

Activity じゃなくて View の内部クラスだったんですね。そして、readJson というクラス名はむしろ悪化してますね…。 それはさておき、肝心の main メソッドが呼ばれてるかどうかは確認しましたか? また、その後の処理についても何が起きてるのかをひとつひとつ確認する必要があるでしょうね。
adakatt12

2022/01/21 05:33

mainメソッドは呼ばれていませんでした。 readJsonクラスを実行したところ下記のエラーが出ていました。gradleまわりのエラーのようです。 FAILURE: Build failed with an exception. * Where: Initialization script 'C:\Users\******\AppData\Local\Temp\readJson_main__.gradle' line: 21 * What went wrong: A problem occurred configuring project ':app'. > Could not create task ':app:readJson.main()'. > SourceSet with name 'main' not found. * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
hoshi-takanori

2022/01/21 05:35

gradle から実行しようとしたんですか? Android アプリの中で呼び出すのではなく?
adakatt12

2022/01/21 08:24

すみません勘違いしていたようです。 今度はAndroidアプリの中から呼び出しました。 public static void main(String[] args) throws JSONException { この行の真下に Log.d("debug", "main start"); を入れてデバッグしたのですがlogcatには表示されていませんでした。 main メソッドが呼ばれていない、ということでしょうか?
hoshi-takanori

2022/01/21 08:53

そのメソッドを呼び出すためのコードを、どこにどのように書きましたか?
guest

回答1

0

ベストアンサー

GPSdata クラスを Destination クラスとし、readFile メソッドを readJson クラスに入れた上で DestinationList クラスとして、読み込みを確認するプログラムとしてみました。

DestinationList destinationList = new DestinationList(this);

でファイルを読み込み、

for(Destination gdata : destinationList) {
Log.d("MainActivity", "gdata="+gdata);
}

で中身を表示させて確認しています。

java

1import androidx.annotation.NonNull; 2import androidx.appcompat.app.AppCompatActivity; 3 4import android.content.Context; 5import android.os.Bundle; 6import android.util.Log; 7 8import org.json.*; 9 10import java.io.*; 11import java.util.*; 12 13class Destination { 14 final String info; 15 final double latitude; 16 final double longitude; 17 18 public Destination(String info, double latitude, double longitude) { 19 this.info = info; 20 this.latitude = latitude; 21 this.longitude = longitude; 22 } 23 24 @Override 25 public String toString() { 26 return "Destination{" + "info='" + info + "', latitude=" + latitude + ", longitude=" + longitude + '}'; 27 } 28} 29 30class DestinationList implements Iterable<Destination> { 31 private List<Destination> destinationList = new ArrayList<>(); 32 33 DestinationList(Context context) { 34 try { 35 String data = readFile(context, "sample.json"); 36 JSONArray jarray = new JSONArray(data); 37 38 for(int i = 0; i < jarray.length(); i++) { 39 JSONObject jobject = jarray.getJSONObject(i); 40 41 String info = jobject.getString("info"); 42 double latitude = jobject.getDouble("latitude"); 43 double longitude = jobject.getDouble("longitude"); 44 45 destinationList.add(new Destination(info, latitude, longitude)); 46 } 47 } catch(JSONException | IOException e) { 48 e.printStackTrace(); 49 } 50 } 51 52 private String readFile(Context context, String filename) throws IOException { 53 File file = new File(context.getFilesDir(), filename); 54 if(!file.exists()) return ""; 55 byte[] buf = new byte[(int)file.length()]; 56 try(InputStream is = new FileInputStream(file);) { 57 is.read(buf); 58 return new String(buf); 59 } 60 } 61 62 public int getSize() { return destinationList.size(); } 63 public Destination get(int i) { return destinationList.get(i); } 64 65 @NonNull 66 @Override 67 public Iterator iterator() { 68 return destinationList.iterator(); 69 } 70} 71 72public class MainActivity extends AppCompatActivity { 73 74 @Override 75 protected void onCreate(Bundle savedInstanceState) { 76 super.onCreate(savedInstanceState); 77 setContentView(R.layout.activity_main); 78 79 try { 80 writeFile(this, "sample.json"); //テストデータ作成 81 82 DestinationList destinationList = new DestinationList(this); 83 84 for(Destination gdata : destinationList) { 85 Log.d("MainActivity", "gdata="+gdata); 86 } 87 } catch(IOException e) { 88 e.printStackTrace(); 89 } 90 } 91 92 private void writeFile(Context context, String filename) throws IOException { 93 File file = new File(context.getFilesDir(), filename); 94 try(PrintWriter pw = new PrintWriter(new FileWriter(file));) { 95 pw.print("[{\n" 96 +" \"info\":\"ここに目的地の名称が入ります\",\n" 97 +" \"latitude\":35.012345,\n" 98 +" \"longitude\":138.012345\n" 99 +"},\n" 100 +"{\n" 101 +" \"info\":\"〇〇〇〇〇〇\",\n" 102 +" \"latitude\":35.67890,\n" 103 +" \"longitude\":138.67890\n" 104 +"}]\n"); 105 } 106 } 107}

実行時ログ

plain

1D/MainActivity: gdata=Destination{info='ここに目的地の名称が入ります', latitude=35.012345, longitude=138.012345} 2 gdata=Destination{info='〇〇〇〇〇〇', latitude=35.6789, longitude=138.6789}

ご提示のコードを以下のように修正することで使用出来ると思います。
(☆=コメント化、★=追加)

java

1 // ARテキストの情報を保持するオブジェクト 2 //private ArrayList<readJson.GPSdata> glist; //☆ 3 private DestinationList destinationList; //★ 4 5 public OverlayView(Context context) { 6 super(context); 7 // 画面サイズの取得 8 Display disp = ((WindowManager) context 9 .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 10 displayX = disp.getWidth(); 11 12 destinationList = new DestinationList(context); //★ 13 }

java

1 // (1)描画処理 2 @Override 3 protected void onDraw(Canvas canvas) { 4 5//略 6 7 //ArrayList<readJson.GPSdata> glist = readJson.jlist; //☆ 8 9 // 追記:ARテキストの描画 10 //for (int i = 0; i < glist.size(); i++) { //☆ 11 for (Destination gdata : destinationList) { //★ 12 // データの読み込み 13 //readJson.GPSdata gdata = glist.get(i); //☆ 14 String info = gdata.info; 15 double y = gdata.latitude; 16 double x = gdata.longitude;

投稿2022/01/21 09:49

編集2022/01/21 09:59
jimbe

総合スコア12646

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/01/21 10:18

回答に関係無いのでこちらに書きますが、基本的に onDraw 内で sleep 等の時間稼ぎはしないでください。 onDraw の呼び出しは表示されている全 View に対し必要に応じて順に行われています。 一部の View で時間稼ぎをすると、他の View の表示・動作に影響し、最終的には android 自体の動作にも波及します。
adakatt12

2022/01/22 07:19

無事こちらの環境で実装することが出来ました。 onDrawの件、承知致しました。ご指摘いただきありがとうございます。 この度は本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問