From 1cd1f2debd15a92a6cdef3fab76550d3e051d026 Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Thu, 26 Jun 2025 08:44:18 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=BB=E5=8F=96nfc=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=92=8C=E5=86=99=E5=85=A5=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 46 +++++- app/src/main/AndroidManifest.xml | 46 ++++-- .../activity/main/MainActivity.java | 117 ++++++++++++- .../activity/nfc/NfcActivity.java | 155 ++++++++++++++++-- .../base/BaseApplication.java | 29 ++++ .../ttstd/elderlyassistant/bean/Contact.java | 53 ++++++ .../elderlyassistant/gson/GsonUtils.java | 144 ++++++++++++++++ .../gson/IntegerDefault0Adapter.java | 35 ++++ .../gson/NullStringToEmptyAdapterFactory.java | 45 +++++ app/src/main/res/layout/activity_main.xml | 36 ++-- app/src/main/res/layout/activity_nfc.xml | 56 ++++++- build.gradle | 10 +- 12 files changed, 713 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/com/ttstd/elderlyassistant/base/BaseApplication.java create mode 100644 app/src/main/java/com/ttstd/elderlyassistant/bean/Contact.java create mode 100644 app/src/main/java/com/ttstd/elderlyassistant/gson/GsonUtils.java create mode 100644 app/src/main/java/com/ttstd/elderlyassistant/gson/IntegerDefault0Adapter.java create mode 100644 app/src/main/java/com/ttstd/elderlyassistant/gson/NullStringToEmptyAdapterFactory.java diff --git a/app/build.gradle b/app/build.gradle index 9fadb35..b1b4d79 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,14 +9,14 @@ def releaseTime() { } android { - compileSdkVersion 33 - buildToolsVersion "30.0.3" + compileSdkVersion 29 +// buildToolsVersion "30.0.3" defaultConfig { applicationId "com.ttstd.elderlyassistant" //There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature. minSdkVersion 23 - targetSdkVersion 33 + targetSdkVersion 29 versionCode 1 versionName "1.0" @@ -92,15 +92,49 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.constraintlayout:constraintlayout:2.0.3' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.2.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + //glide + implementation 'com.github.bumptech.glide:glide:4.13.1' + annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1' + //RxJava + implementation 'io.reactivex.rxjava3:rxjava:3.0.0' + implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' + // + implementation 'com.squareup.okhttp3:okhttp:4.7.0' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' +// implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' + implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" + //Gson + implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.zxing:core:3.5.0' + //生命周期管理 + implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-components:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-components-preference:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle:4.0.2' + + implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0' + /*https://github.com/JeremyLiao/LiveEventBus*/ + implementation 'com.jeremyliao:live-event-bus-x:1.7.3' //MMKV implementation 'com.tencent:mmkv-static:1.2.14' //bugly implementation 'com.tencent.bugly:crashreport:4.1.9.2' implementation 'com.iqiyi.xcrash:xcrash-android-lib:3.0.0' + + //工具类 + implementation 'com.blankj:utilcodex:1.31.0' + //autosize会改变第三方view的大小 + //https://github.com/JessYanCoding/AndroidAutoSize + implementation 'me.jessyan:autosize:1.2.1' + // 吐司框架:https://github.com/getActivity/Toaster + implementation 'com.github.getActivity:Toaster:12.6' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9e6a782..da6e42c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,11 +5,13 @@ - - + - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -58,7 +71,12 @@ android:resource="@xml/accessibility_service_config" /> - + + \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/elderlyassistant/activity/main/MainActivity.java b/app/src/main/java/com/ttstd/elderlyassistant/activity/main/MainActivity.java index b5425af..d0f7aeb 100644 --- a/app/src/main/java/com/ttstd/elderlyassistant/activity/main/MainActivity.java +++ b/app/src/main/java/com/ttstd/elderlyassistant/activity/main/MainActivity.java @@ -1,16 +1,127 @@ package com.ttstd.elderlyassistant.activity.main; -import androidx.appcompat.app.AppCompatActivity; - +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; +import android.nfc.Tag; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcF; import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; import com.ttstd.elderlyassistant.R; +import com.ttstd.elderlyassistant.activity.nfc.NfcActivity; +import com.ttstd.elderlyassistant.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { + private static final String TAG = "MainActivity"; + + private ActivityMainBinding mBinding; + + private NfcManager mNfcManager; + private NfcAdapter mNfcAdapter; + private Tag mTag; + private PendingIntent pendingIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); +// setContentView(R.layout.activity_main); + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); + mBinding.setClick(new BtnClick()); + + + mNfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE); + if (mNfcManager == null) { + // 设备不支持 NFC + Toast.makeText(this, "设备不支持 NFC", Toast.LENGTH_SHORT).show(); + finish(); + } + + mNfcAdapter = mNfcManager.getDefaultAdapter(); + if (mNfcAdapter == null) { + // 设备不支持 NFC + Toast.makeText(this, "设备不支持 NFC", Toast.LENGTH_SHORT).show(); + finish(); + } + + // 创建 PendingIntent 捕获 NFC 事件 + pendingIntent = PendingIntent.getActivity( + this, 0, + new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), + PendingIntent.FLAG_IMMUTABLE + ); + } + + @Override + protected void onResume() { + super.onResume(); + if (mNfcAdapter != null) { + // 指定处理 TECH_DISCOVERED 类型标签 + IntentFilter[] filters = new IntentFilter[]{ + new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED) + }; + String[][] techLists = new String[][]{ + {NfcF.class.getName(), MifareClassic.class.getName()} + }; + mNfcAdapter.enableForegroundDispatch(this, pendingIntent, filters, techLists); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mNfcAdapter != null) { + mNfcAdapter.disableForegroundDispatch(this); + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Log.e(TAG, "onNewIntent: "); + if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) { + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + if (tag != null) { + // 获取 NFC ID (16 进制格式) + byte[] idBytes = tag.getId(); + String tagId = bytesToHex(idBytes); + + // 读取 NDEF 数据(如为文本标签) + Ndef ndef = Ndef.get(tag); + if (ndef != null) { + NdefMessage ndefMessage = ndef.getCachedNdefMessage(); + if (ndefMessage != null) { + String payload = new String(ndefMessage.getRecords()[0].getPayload()); + Log.e(TAG, "onNewIntent: payload = " + payload); + } + } + } + } + } + + // 字节数组转 Hex 字符串 + private String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } + + public class BtnClick { + public void wirteTag(View view) { + startActivity(new Intent(MainActivity.this, NfcActivity.class)); + } } } diff --git a/app/src/main/java/com/ttstd/elderlyassistant/activity/nfc/NfcActivity.java b/app/src/main/java/com/ttstd/elderlyassistant/activity/nfc/NfcActivity.java index 3354edc..8b260dd 100644 --- a/app/src/main/java/com/ttstd/elderlyassistant/activity/nfc/NfcActivity.java +++ b/app/src/main/java/com/ttstd/elderlyassistant/activity/nfc/NfcActivity.java @@ -1,64 +1,183 @@ package com.ttstd.elderlyassistant.activity.nfc; -import androidx.appcompat.app.AppCompatActivity; - import android.content.Context; import android.content.Intent; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcManager; +import android.nfc.Tag; +import android.nfc.tech.Ndef; import android.os.Bundle; import android.os.Parcelable; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; import android.widget.Toast; -import com.ttstd.elderlyassistant.R; +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; +import com.hjq.toast.Toaster; +import com.ttstd.elderlyassistant.R; +import com.ttstd.elderlyassistant.bean.Contact; +import com.ttstd.elderlyassistant.databinding.ActivityNfcBinding; + +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Locale; + +import com.ttstd.elderlyassistant.gson.GsonUtils; public class NfcActivity extends AppCompatActivity { + private static final String TAG = "NfcActivity"; + + private ActivityNfcBinding mBinding; + + private NfcManager mNfcManager; + private NfcAdapter mNfcAdapter; + private Tag mTag; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_nfc); + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_nfc); +// setContentView(R.layout.activity_nfc); + mBinding.setClick(new BtnClick()); - NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE); - NfcAdapter nfcAdapter = manager.getDefaultAdapter(); - - if (nfcAdapter == null) { + mNfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE); + if (mNfcManager == null) { // 设备不支持 NFC Toast.makeText(this, "设备不支持 NFC", Toast.LENGTH_SHORT).show(); finish(); } + mNfcAdapter = mNfcManager.getDefaultAdapter(); + if (mNfcAdapter == null) { + // 设备不支持 NFC + Toast.makeText(this, "设备不支持 NFC", Toast.LENGTH_SHORT).show(); + finish(); + } + + Intent intent = getIntent(); + getMessageFromIntent(intent); + } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { - Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - if (rawMessages != null) { - NdefMessage[] messages = new NdefMessage[rawMessages.length]; - for (int i = 0; i < rawMessages.length; i++) { - messages[i] = (NdefMessage) rawMessages[i]; + getMessageFromIntent(intent); + } + + private void getMessageFromIntent(Intent intent) { + String action = intent.getAction(); + Log.e(TAG, "getMessageFromIntent: action = " + action); + switch (action) { + case NfcAdapter.ACTION_NDEF_DISCOVERED: + Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMessages != null) { + NdefMessage[] messages = new NdefMessage[rawMessages.length]; + for (int i = 0; i < rawMessages.length; i++) { + messages[i] = (NdefMessage) rawMessages[i]; + } + // 处理 NDEF 消息 + processNdefMessages(messages); } - // 处理 NDEF 消息 - processNdefMessages(messages); - } + break; + case NfcAdapter.ACTION_TECH_DISCOVERED: + mTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + if (mTag != null) { + // 获取 NFC ID (16 进制格式) + byte[] idBytes = mTag.getId(); + String tagId = bytesToHex(idBytes); + Log.e(TAG, "getMessageFromIntent: tagId = " + tagId); + // 读取 NDEF 数据(如为文本标签) + Ndef ndef = Ndef.get(mTag); + if (ndef != null) { + NdefMessage ndefMessage = ndef.getCachedNdefMessage(); + if (ndefMessage != null) { + String payload = new String(ndefMessage.getRecords()[0].getPayload()); + Log.e(TAG, "getMessageFromIntent: payload = " + payload); + } else { + Log.e(TAG, "getMessageFromIntent: ndefMessage is null"); + } + } + } + break; } } + // 字节数组转 Hex 字符串 + private String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } + private void processNdefMessages(NdefMessage[] messages) { for (NdefMessage message : messages) { for (NdefRecord record : message.getRecords()) { if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) { // 处理文本记录 String text = new String(record.getPayload()); - Toast.makeText(this, "NFC 数据: " + text, Toast.LENGTH_SHORT).show(); + Toaster.show("NFC 数据: " + text); + } } } } + + public void writeTag(String text, Tag tag) { + try { + NdefRecord record = createTextRecord(text, Locale.ENGLISH); + NdefMessage message = new NdefMessage(new NdefRecord[]{record}); + + Ndef ndef = Ndef.get(tag); + if (ndef != null) { + ndef.connect(); + ndef.writeNdefMessage(message); + Toaster.show("写入成功: "); + } + } catch (Exception e) { + Toaster.show("写入失败: " + e.getMessage()); + } + } + + // 创建 NDEF 文本记录 + private NdefRecord createTextRecord(String text, Locale locale) { + byte[] langBytes = locale.getLanguage().getBytes(StandardCharsets.US_ASCII); + byte[] textBytes = text.getBytes(StandardCharsets.UTF_8); + + byte[] payload = new byte[1 + langBytes.length + textBytes.length]; + payload[0] = (byte) langBytes.length; // 状态字节 + System.arraycopy(langBytes, 0, payload, 1, langBytes.length); + System.arraycopy(textBytes, 0, payload, 1 + langBytes.length, textBytes.length); + + return new NdefRecord( + NdefRecord.TNF_WELL_KNOWN, + NdefRecord.RTD_TEXT, + new byte[0], + payload + ); + } + + public class BtnClick { + public void write(View view) { + String name = mBinding.etName.getText().toString(); + String phone = mBinding.etPhone.getText().toString(); + if (TextUtils.isEmpty(name)) { + Toaster.show("请输入联系人姓名"); + return; + } + if (TextUtils.isEmpty(phone)) { + Toaster.show("请输入联系人手机号"); + return; + } + Contact contact = new Contact(name, phone); + writeTag(GsonUtils.toJSONString(contact), mTag); + } + } } diff --git a/app/src/main/java/com/ttstd/elderlyassistant/base/BaseApplication.java b/app/src/main/java/com/ttstd/elderlyassistant/base/BaseApplication.java new file mode 100644 index 0000000..460d4ba --- /dev/null +++ b/app/src/main/java/com/ttstd/elderlyassistant/base/BaseApplication.java @@ -0,0 +1,29 @@ +package com.ttstd.elderlyassistant.base; + +import android.app.Application; + +import com.hjq.toast.Toaster; + +public class BaseApplication extends Application { + + @Override + public void onCreate() { + super.onCreate(); + Toaster.init(this); + } + + @Override + public void onTerminate() { + super.onTerminate(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + } +} diff --git a/app/src/main/java/com/ttstd/elderlyassistant/bean/Contact.java b/app/src/main/java/com/ttstd/elderlyassistant/bean/Contact.java new file mode 100644 index 0000000..d3f443e --- /dev/null +++ b/app/src/main/java/com/ttstd/elderlyassistant/bean/Contact.java @@ -0,0 +1,53 @@ +package com.ttstd.elderlyassistant.bean; + +import java.io.Serializable; + +public class Contact implements Serializable { + private static final long serialVersionUID = -5570426400839799887L; + + String name; + String phone; + String tag; + /** + * 0 电话 1 短信 2 微信语音 3 微信视频 + */ + int defaultOperation; + int version; + + + public Contact() { + + } + + public Contact(String name, String phone) { + this.name = name; + this.phone = phone; + this.defaultOperation = 3; + this.version = 1; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } +} diff --git a/app/src/main/java/com/ttstd/elderlyassistant/gson/GsonUtils.java b/app/src/main/java/com/ttstd/elderlyassistant/gson/GsonUtils.java new file mode 100644 index 0000000..c8b11ca --- /dev/null +++ b/app/src/main/java/com/ttstd/elderlyassistant/gson/GsonUtils.java @@ -0,0 +1,144 @@ +package com.ttstd.elderlyassistant.gson; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +public class GsonUtils { + //https://blog.csdn.net/zte1055889498/article/details/122400299 + + public static JsonObject getJsonObject(String jsonString) { + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + return jsonObject; + } + + private static final Gson gson; + + static { + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()); + builder.registerTypeAdapter(Integer.class, new IntegerDefault0Adapter()); + builder.registerTypeAdapter(int.class, new IntegerDefault0Adapter()); + builder.disableHtmlEscaping(); + builder.enableComplexMapKeySerialization(); + // builder.excludeFieldsWithoutExposeAnnotation(); + builder.setDateFormat("yyyy-MM-dd HH:mm:ss"); + gson = builder.create(); + } + + public static Type makeJavaType(Type rawType, Type... typeArguments) { + return TypeToken.getParameterized(rawType, typeArguments).getType(); + } + + public static String toString(Object value) { + if (Objects.isNull(value)) { + return null; + } + if (value instanceof String) { + return (String) value; + } + return toJSONString(value); + } + + public static String toJSONString(Object value) { + return gson.toJson(value); + } + + public static String toPrettyString(Object value) { + return gson.newBuilder().setPrettyPrinting().create().toJson(value); + } + + public static JsonElement fromJavaObject(Object value) { + JsonElement result = null; + if (Objects.nonNull(value) && (value instanceof String)) { + result = parseObject((String) value); + } else { + result = gson.toJsonTree(value); + } + return result; + } + + public static JsonElement parseObject(String content) { + return JsonParser.parseString(content); + } + + public static JsonElement getJsonElement(JsonObject node, String name) { + return node.get(name); + } + + public static JsonElement getJsonElement(JsonArray node, int index) { + return node.get(index); + } + + public static T toJavaObject(JsonElement node, Class clazz) { + return gson.fromJson(node, clazz); + } + + public static T toJavaObject(JsonElement node, Type type) { + return gson.fromJson(node, type); + } + + public static T toJavaObject(JsonElement node, TypeToken typeToken) { + return toJavaObject(node, typeToken.getType()); + } + + public static List toJavaList(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static T toJavaObject(String content, Class clazz) { + JsonObject jsonObject = getJsonObject(content); + String jsonString = jsonObject.toString(); + return gson.fromJson(jsonString, clazz); + } + + public static T toJavaObject(String content, Type type) { + return gson.fromJson(content, type); + } + + public static T toJavaObject(String content, TypeToken typeToken) { + return toJavaObject(content, typeToken.getType()); + } + + public static List toJavaList(String content, Class clazz) { + return toJavaObject(content, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(String content, Class clazz) { + return toJavaObject(content, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } +} diff --git a/app/src/main/java/com/ttstd/elderlyassistant/gson/IntegerDefault0Adapter.java b/app/src/main/java/com/ttstd/elderlyassistant/gson/IntegerDefault0Adapter.java new file mode 100644 index 0000000..3d33889 --- /dev/null +++ b/app/src/main/java/com/ttstd/elderlyassistant/gson/IntegerDefault0Adapter.java @@ -0,0 +1,35 @@ +package com.ttstd.elderlyassistant.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonSyntaxException; + +import java.lang.reflect.Type; + +public class IntegerDefault0Adapter implements JsonSerializer, JsonDeserializer { + @Override + public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + try { + if (json.getAsString().equals("")) { + return 0; + } + } catch (Exception ignore) { + } + try { + return json.getAsInt(); + } catch (NumberFormatException e) { + throw new JsonSyntaxException(e); + } + } + + @Override + public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/elderlyassistant/gson/NullStringToEmptyAdapterFactory.java b/app/src/main/java/com/ttstd/elderlyassistant/gson/NullStringToEmptyAdapterFactory.java new file mode 100644 index 0000000..bf885a8 --- /dev/null +++ b/app/src/main/java/com/ttstd/elderlyassistant/gson/NullStringToEmptyAdapterFactory.java @@ -0,0 +1,45 @@ +package com.ttstd.elderlyassistant.gson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +public class NullStringToEmptyAdapterFactory implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + + Class rawType = (Class) type.getRawType(); + if (rawType != String.class) { + return null; + } + return (TypeAdapter) new StringAdapter(); + } + + public static class StringAdapter extends TypeAdapter { + @Override + public String read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return ""; + } + return reader.nextString(); + } + + @Override + public void write(JsonWriter writer, String value) throws IOException { + if (value == null) { + writer.nullValue(); + return; + } + writer.value(value); + } + } + +} + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c2f34a7..d87d369 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,18 +1,30 @@ - - + - \ No newline at end of file + + + + + +