WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 2b537ac

Browse files
committed
update
1 parent a54db62 commit 2b537ac

16 files changed

+346
-37
lines changed

.idea/AndroidProjectSystem.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/compiler.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deploymentTargetSelector.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ try {
1111
}
1212
android {
1313
namespace 'com.template.androidbasicapp'
14-
compileSdk 34
14+
compileSdk 35
1515

1616
defaultConfig {
1717
applicationId "com.template.androidbasicapp" // TODO applicationIdを他の人と被らない名前に変更してください。
1818
minSdk 29
19-
targetSdk 34
19+
targetSdk 35
2020
versionCode 130
2121
versionName "1.3.0"
2222

@@ -54,8 +54,8 @@ android {
5454
}
5555

5656
compileOptions {
57-
sourceCompatibility JavaVersion.VERSION_1_8
58-
targetCompatibility JavaVersion.VERSION_1_8
57+
sourceCompatibility JavaVersion.VERSION_21
58+
targetCompatibility JavaVersion.VERSION_21
5959
}
6060

6161
buildFeatures {
@@ -88,25 +88,34 @@ android {
8888

8989
dependencies {
9090
// UI
91-
implementation("androidx.appcompat:appcompat:1.6.1")
92-
implementation("com.google.android.material:material:1.10.0")
93-
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
94-
implementation("androidx.lifecycle:lifecycle-livedata:2.6.2")
95-
implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.2")
96-
implementation("androidx.navigation:navigation-fragment:2.7.4")
97-
implementation("androidx.navigation:navigation-ui:2.7.4")
98-
implementation 'com.google.android.gms:play-services-maps:18.2.0'
91+
implementation("androidx.appcompat:appcompat:1.7.0")
92+
implementation("com.google.android.material:material:1.12.0")
93+
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
94+
implementation("androidx.lifecycle:lifecycle-livedata:2.9.0")
95+
implementation("androidx.lifecycle:lifecycle-viewmodel:2.9.0")
96+
implementation("androidx.navigation:navigation-fragment:2.9.0")
97+
implementation("androidx.navigation:navigation-ui:2.9.0")
98+
implementation 'com.google.android.gms:play-services-maps:19.2.0'
9999

100100
// Unit Test
101101
testImplementation("junit:junit:4.13.2")
102-
androidTestImplementation("androidx.test.ext:junit:1.1.5")
103-
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
102+
androidTestImplementation("androidx.test.ext:junit:1.2.1")
103+
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
104104

105105
// Local Database - Room
106-
def room_version = "2.5.0"
106+
def room_version = "2.7.1"
107107
implementation("androidx.room:room-runtime:$room_version")
108108
annotationProcessor("androidx.room:room-compiler:$room_version")
109109

110110
// Image
111111
implementation "com.github.bumptech.glide:glide:4.13.2"
112+
113+
// Retrofit & okhttp3 & Gsonライブラリの追加 (Rxjavaは導入しない) - START
114+
def retrofitVersion = "2.11.0"
115+
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
116+
implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
117+
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0"))
118+
implementation("com.squareup.okhttp3:okhttp")
119+
implementation("com.squareup.okhttp3:logging-interceptor")
120+
// END
112121
}

app/proguard-rules.pro

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@
1818

1919
# If you keep the line number information, uncomment this to
2020
# hide the original source file name.
21-
#-renamesourcefileattribute SourceFile
21+
#-renamesourcefileattribute SourceFile
22+
23+
# keep data package
24+
-keep class com.template.androidbasicapp.data.** { *; }
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.template.androidbasicapp.data;
2+
3+
import androidx.annotation.NonNull;
4+
5+
import com.template.androidbasicapp.BuildConfig;
6+
import com.template.androidbasicapp.exception.AppException;
7+
import com.template.androidbasicapp.exception.AppExceptionType;
8+
9+
import java.io.IOException;
10+
import java.net.HttpURLConnection;
11+
import java.net.SocketException;
12+
import java.net.SocketTimeoutException;
13+
14+
import okhttp3.Interceptor;
15+
import okhttp3.OkHttpClient;
16+
import okhttp3.Response;
17+
import okhttp3.logging.HttpLoggingInterceptor;
18+
import retrofit2.Call;
19+
import retrofit2.Retrofit;
20+
import retrofit2.converter.gson.GsonConverterFactory;
21+
22+
/**
23+
* RetrofitやOkHttpClientのインスタンスは基本的にアプリケーション全体で1つだけ(シングルトン)にするのが推奨される。
24+
* 理由は以下の通り。
25+
* Retrofitの生成コストが高いため、複数生成は非効率。
26+
* RetrofitインスタンスをAPIごとに1つずつシングルトンで持つ設計が一般的。
27+
*/
28+
public final class ApiClient {
29+
private static volatile GithubApiService githubApiService;
30+
private static volatile OkHttpClient okHttpClient;
31+
32+
private ApiClient() {
33+
throw new UnsupportedOperationException("ApiClient is a utility class and cannot be instantiated");
34+
}
35+
36+
/**
37+
* 通信ログをLogcatで確認できるようにInterceptorを追加したOkHttpClientを取得する。
38+
* Logcatから「package:mine tag:okhttp.OkHttpClient」でフィリタリングすると確認しやすい。
39+
* <p>
40+
* スレッドセーフなシングルトンの実装はRoomライブラリなどの内部実装でも採用しているダブルチェックロッキングのパターンを採用した
41+
*
42+
* @return OkHttpClientのインスタンス
43+
*/
44+
private static OkHttpClient getOkHttpClient() {
45+
if (okHttpClient == null) {
46+
synchronized (ApiClient.class) {
47+
if (okHttpClient == null) {
48+
var builder = new OkHttpClient.Builder();
49+
if (BuildConfig.DEBUG) { // デバッグビルドの場合は、通信ログを出力する
50+
var loggingInterceptor = new HttpLoggingInterceptor();
51+
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
52+
builder.addInterceptor(loggingInterceptor);
53+
}
54+
okHttpClient = builder.addInterceptor(new Interceptor() {
55+
@NonNull
56+
@Override
57+
public Response intercept(@NonNull Chain chain) throws IOException {
58+
var url = chain.request().url(); // リクエストURLを取得
59+
var host = url.host(); // ホスト名を取得
60+
61+
if (host.equals("api.github.com")) { // github.comのAPIの場合
62+
// APIで必要なヘッダ情報は、ここで追加することも可能.
63+
return chain.proceed(chain.request().newBuilder()
64+
.addHeader("Accept", "application/vnd.github+json")
65+
.addHeader("X-GitHub-Api-Version", "2022-11-28")
66+
//.addHeader("Authorization", "Bearer TOKEN")
67+
.build());
68+
} else {
69+
// それ以外のAPIは特にヘッダを追加する必要はない
70+
return chain.proceed(chain.request());
71+
}
72+
}
73+
})
74+
.build();
75+
}
76+
}
77+
}
78+
return okHttpClient;
79+
}
80+
81+
public static GithubApiService getGithubApiService() {
82+
if (githubApiService == null) {
83+
synchronized (ApiClient.class) {
84+
if (githubApiService == null) {
85+
var retrofit = new Retrofit.Builder()
86+
.baseUrl("https://api.github.com/")
87+
.client(getOkHttpClient())
88+
.addConverterFactory(GsonConverterFactory.create())
89+
.build();
90+
githubApiService = retrofit.create(GithubApiService.class);
91+
}
92+
}
93+
}
94+
return githubApiService;
95+
}
96+
97+
/**
98+
* RetrofitのCallを実行し、レスポンスボディを取得する.<br>
99+
* Web API固有の処理が入る場合は、共通利用せずに、各APIでdataOrThrowメソッドを用意するのも良いかも<br>
100+
*
101+
* @param call RetrofitのCallオブジェクト
102+
* @param <T> レスポンスボディの型
103+
* @return レスポンスボディ
104+
* @throws AppException 通信エラーやレスポンスエラーが発生した場合にスローされる
105+
*/
106+
public static <T> T dataOrThrow(@NonNull final Call<T> call) throws AppException {
107+
try {
108+
var response = call.execute(); // 通信を実行
109+
var body = response.body(); // レスポンスボディを取得
110+
var code = response.code(); // レスポンスコードを取得
111+
if (response.isSuccessful() && body != null) {
112+
return body; // 成功時はレスポンスボディを返す
113+
} else { // 失敗時はレスポンスコードに応じて例外をスロー
114+
if (code == HttpURLConnection.HTTP_UNAUTHORIZED) {
115+
throw new AppException("Unauthorized access", AppExceptionType.Unauthorized);
116+
} else if (code == HttpURLConnection.HTTP_FORBIDDEN) {
117+
throw new AppException("Forbidden access", AppExceptionType.Forbidden);
118+
} else {// 想定できていないエラーは一旦Unknownでまとめる
119+
throw new AppException("error HTTP code: " + code, AppExceptionType.Unknown);
120+
}
121+
}
122+
} catch (IOException e) { // 通信処理に失敗した場合はIOExceptionをスロー
123+
var message = e.getMessage() != null ? e.getMessage() : "error message is null";
124+
if (e instanceof SocketTimeoutException || e instanceof SocketException) {
125+
throw new AppException(message, AppExceptionType.Network);
126+
} else {
127+
// 想定できていないエラーは一旦Unknownでまとめる
128+
throw new AppException(message, AppExceptionType.Unknown);
129+
}
130+
}
131+
}
132+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.template.androidbasicapp.data;
2+
3+
import retrofit2.Call;
4+
import retrofit2.http.GET;
5+
import retrofit2.http.Query;
6+
7+
/**
8+
* Web API単位でインターフェースを定義する
9+
*/
10+
public interface GithubApiService {
11+
@GET("search/repositories")
12+
Call<GithubSearchResponse> searchRepositories(@Query("q") String q, @Query("sort") String sort);
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.template.androidbasicapp.data;
2+
3+
import androidx.annotation.NonNull;
4+
5+
import com.google.gson.annotations.SerializedName;
6+
7+
import java.util.List;
8+
9+
public record GithubSearchResponse(@SerializedName("total_count") int totalCount,
10+
@SerializedName("incomplete_results") boolean incompleteResults,
11+
@NonNull List<Item> items) {
12+
record Item(long id, @NonNull String name, Owner owner, @NonNull String html_url,
13+
int stargazers_count, int forks_count) {
14+
record Owner(@NonNull String login) {
15+
}
16+
}
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.template.androidbasicapp.exception;
2+
3+
import androidx.annotation.NonNull;
4+
5+
/**
6+
* ベースとなるアプリケーション固有のException
7+
*/
8+
public class AppException extends Exception {
9+
private final AppExceptionType type;
10+
11+
public AppException(@NonNull final String message, @NonNull final AppExceptionType type) {
12+
super(message);
13+
this.type = type;
14+
}
15+
16+
public AppExceptionType getType() {
17+
return type;
18+
}
19+
}

0 commit comments

Comments
 (0)