app/build.gradle
@@ -80,4 +80,37 @@ implementation 'com.pnikosis:materialish-progress:1.7' //推送相关 // 此处以JPush 5.0.0 版本为例,5.0.0 版本开始可以自动拉取 JCore 包,无需另外配置 implementation 'cn.jiguang.sdk:jpush:5.2.2' //若不集成厂商通道,可直接跳过以下依赖 // 极光厂商插件版本与接入 JPush 版本保持一致,下同 // 接入华为厂商 implementation 'com.huawei.hms:push:6.5.0.300' implementation 'cn.jiguang.sdk.plugin:huawei:5.2.2' // 接入 FCM 厂商 implementation 'com.google.firebase:firebase-messaging:23.0.5' implementation 'cn.jiguang.sdk.plugin:fcm:5.2.2' // 接入魅族厂商 implementation 'cn.jiguang.sdk.plugin:meizu:5.2.2' // 接入 VIVO 厂商 implementation 'cn.jiguang.sdk.plugin:vivo:5.2.2' // 接入小米厂商 implementation 'cn.jiguang.sdk.plugin:xiaomi:5.2.2' // 接入 OPPO 厂商 implementation 'cn.jiguang.sdk.plugin:oppo:5.2.2' // JPush Android SDK v4.6.0 开始,需要单独引入 oppo 厂商 aar ,请下载官网 SDK 包并把 jpush-android-xxx-release/third-push/oppo/libs 下的 aar 文件单独拷贝一份到应用 module/libs 下 implementation(name: 'com.heytap.msp-push-3.1.0', ext: 'aar') //以下为 OPPO 3.1.0 aar需要依赖 implementation 'com.google.code.gson:gson:2.6.2' implementation 'commons-codec:commons-codec:1.6' implementation 'androidx.annotation:annotation:1.1.0' // 接入荣耀厂商 implementation 'cn.jiguang.sdk.plugin:honor:5.2.2' // apply plugin: 'com.google.gms.google-services' apply plugin: 'com.huawei.agconnect' } app/src/main/AndroidManifest.xml
@@ -26,8 +26,31 @@ </intent-filter> </activity> <!-- <activity android:name=".activity.MainActivity" />--> <!-- Required since 5.2.0 --> <!-- 新的 tag/alias 接口结果返回需要开发者配置一个自定义的Service --> <!-- 3.3.0开始所有事件将通过该类回调 --> <!-- 5.2.0开始所有事件将通过该类回调 --> <!-- 该广播需要继承 JPush 提供的 JPushMessageService 类, 并如下新增一个 Intent-Filter --> <service android:name=".service.PushService" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="cn.jpush.android.intent.SERVICE_MESSAGE" /> <category android:name="com.dayu.pipirrapp" /> </intent-filter> </service> <!-- Since JCore2.0.0 Required SDK核心功能--> <!-- 可配置android:process参数将Service放在其他进程中;android:enabled属性不能是false --> <!-- 这个是自定义Service,要继承极光JCommonService,可以在更多手机平台上使得推送通道保持的更稳定 --> <service android:name="xx.xx.XService" android:enabled="true" android:exported="false" android:process=":pushcore"> <intent-filter> <action android:name="cn.jiguang.user.service.action" /> </intent-filter> </service> </application> </manifest> app/src/main/java/com/dayu/pipirrapp/MyApplication.java
@@ -2,6 +2,8 @@ import android.app.Application; import cn.jpush.android.api.JPushInterface; /** * author: zuo * Date: 2023/12/21 @@ -15,5 +17,7 @@ public void onCreate() { super.onCreate(); myApplication = this; JPushInterface.setDebugMode(true); JPushInterface.init(this); } } app/src/main/java/com/dayu/pipirrapp/activity/MainActivity.java
@@ -1,9 +1,11 @@ package com.dayu.pipirrapp.activity; import android.os.Bundle; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; @@ -49,5 +51,21 @@ binding.tabLayout.setupWithViewPager(binding.viewPager); } long mExitTime; //点击两次退出程序 有时间间隔 间隔内点击则退出程序 否则 则提示 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if ((System.currentTimeMillis() - mExitTime) > 2000) { Toast.makeText(MainActivity.this, "再按一次退出程序", Toast.LENGTH_SHORT).show(); mExitTime = System.currentTimeMillis(); } else { MainActivity.this.finish(); } return true; } return super.onKeyDown(keyCode, event); } } app/src/main/java/com/dayu/pipirrapp/adapter/TabAdapter.java
@@ -35,9 +35,22 @@ return 3; // 假设有三个标签 } // @Override // public CharSequence getPageTitle(int position) { // // 返回标签的标题 // return "Tab " + (position + 1); // } @Override public CharSequence getPageTitle(int position) { String text = ""; switch (position) { case 0: text = "首页"; break; case 1: text = "地图"; break; case 2: text = "我的"; break; } // 返回标签的标题 return text; } } app/src/main/java/com/dayu/pipirrapp/net/ApiManager.java
New file @@ -0,0 +1,155 @@ package com.dayu.pipirrapp.net; import android.content.Context; import com.dayu.pipirrapp.net.subscribers.BaseProgressSubscriber; import com.dayu.pipirrapp.net.subscribers.ProgressSubscriber; import com.dayu.pipirrapp.net.subscribers.SubscriberListener; import com.dayu.pipirrapp.utils.MyJsonParser; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Objects; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.schedulers.Schedulers; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; /** * Copyright (C), 2023, * Author: zuot * Date: 2023-04-12 9:11 * Description: */ public class ApiManager { static ApiManager apiManager; //文件上传失败重复次数 int uplodFilerepeatSize = 3; ApiService apiService; public static void init() { if (apiManager == null) { apiManager = new ApiManager(); } } public ApiManager() { apiService = RetrofitClient.getInstance().getApiService(); } public static ApiManager getInstance() { return apiManager; } public <T> void requestPostLoading(final Context context, final String path, final Class<T> tClass, final Map<String, Object> params, final SubscriberListener listener) { request(context, false, path, false, tClass, params, listener); } public <T> void requestPostHideLoading(final Context context, final String path, final Class<T> tClass, final Map<String, Object> params, final SubscriberListener listener) { request(context, true, path, false, tClass, params, listener); } public <T> void requestPost(final Context context, final String path, final Class<T> tClass, final Map<String, Object> params, final SubscriberListener listener) { request(context, false, path, false, tClass, params, listener); } /** * 发送请求 * * @param context * @param hideLoading 是否显示加载框 false:显示 true:隐藏 * @param path 请求路径,在UrlConfig中定义 * @param isGet 是否是Get请求 true:get 请求 * @param tClass 对应的数据类型 * @param params Post请求时,对应的参数 * @param listener 回调请求 * @param <T> */ public <T> void request(final Context context, final boolean hideLoading, final String path, final boolean isGet, final Class<T> tClass, final Map<String, Object> params, final SubscriberListener listener) { Observable observable; BaseProgressSubscriber<?> mySubscriber; if (isGet) { if (params == null) { observable = apiService.requestGet(path); } else { observable = apiService.requestGet(path, params); } } else { observable = apiService.requestPost(path, params); } mySubscriber = new ProgressSubscriber(context, hideLoading, listener); observable.subscribeOn(Schedulers.io()). map(new Function<Object, BaseResponse<T>>() { @Override public BaseResponse<T> apply(Object o) { if (o instanceof BaseResponse) { BaseResponse tem = (BaseResponse) o; BaseResponse<T> response = new BaseResponse<>(); response.setCode(tem.getCode()); response.setMsg(tem.getMsg()); if (tClass != null && tem.getContent() instanceof Map) { try { // response.setData(MyJsonParser.getBeanFromMap((Map<String, Object>) tem.getData(), tClass)); String jsonData = MyJsonParser.getJsontoMap((Map) tem.getContent()); response.setContent(MyJsonParser.getBeanFromJson(jsonData, tClass)); } catch (Exception e) { e.printStackTrace(); } } else if (tClass != null && tem.getContent() instanceof List) { try { response.setContent((T) MyJsonParser.getListByJson(MyJsonParser.getJsonbyList((List) tem.getContent()), tClass)); } catch (Exception e) { e.printStackTrace(); } } else if (tClass != null && tem.getContent() instanceof Integer) { response.setContent((T) tem.getContent()); } if (tClass != null && tClass.getName() instanceof String && tem.getContent() instanceof String) { try { response.setContent((T) tem.getContent()); } catch (Exception e) { e.printStackTrace(); } } return response; } return null; } }) .unsubscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(mySubscriber); } } app/src/main/java/com/dayu/pipirrapp/net/BaseResponse.java
@@ -9,7 +9,7 @@ public class BaseResponse<T> { private int code; private String msg; private T data; private T content; private String stackErrorInfo;//堆栈错误描述 @@ -51,12 +51,11 @@ this.stackErrorInfo = stackErrorInfo; } public T getData() { return data; public T getContent() { return content; } public void setData(T data) { this.data = data; public void setContent(T content) { this.content = content; } } app/src/main/java/com/dayu/pipirrapp/net/progress/NetLoadingDialog.java
New file @@ -0,0 +1,68 @@ package com.dayu.pipirrapp.net.progress; import android.app.Dialog; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.view.Gravity; import com.dayu.pipirrapp.R; import com.pnikosis.materialishprogress.ProgressWheel; /** * Copyright (C), 2023, * Author: zuo * Date: 2023-04-12 9:32 * Description: */ public class NetLoadingDialog extends Dialog { //private TextView mMessage; private AnimationDrawable mAnimationDrawable; public NetLoadingDialog(Context context) { super(context, R.style.Theme_PipIrrApp); init(); } private void init() { try { int ws_pay_net_loading, iv_net_loading_anim; getWindow().setGravity(Gravity.CENTER); setContentView(R.layout.net_loding); setCanceledOnTouchOutside(false); ProgressWheel wheel = findViewById(R.id.progress_wheel); } catch (Exception e) { e.printStackTrace(); } } public void startAnim() { try { this.show(); // mHandler.postDelayed(new Runnable() { // @Override // public void run() { // mAnimationDrawable.start(); // } // }, 100); } catch (Exception e) { } } public void stopAnim() { try { // mAnimationDrawable.stop(); this.dismiss(); } catch (Exception e) { } } } app/src/main/java/com/dayu/pipirrapp/net/progress/ProgressCancelListener.java
New file @@ -0,0 +1,9 @@ package com.dayu.pipirrapp.net.progress; /** * Created by qwy on 16/3/10. * 取消进度框监听 */ public interface ProgressCancelListener { void onCancelProgress(); } app/src/main/java/com/dayu/pipirrapp/net/progress/ProgressDialogHandler.java
New file @@ -0,0 +1,84 @@ package com.dayu.pipirrapp.net.progress; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; /** * Created by qwy on 16/3/10. * 展示进度对话框 */ public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESS_DIALOG = 1; public static final int DISMISS_PROGRESS_DIALOG = 2; private NetLoadingDialog pd; private Context context; private boolean cancelable; private ProgressCancelListener mProgressCancelListener; public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener, boolean cancelable) { super(); this.context = context; this.mProgressCancelListener = mProgressCancelListener; this.cancelable = cancelable; } private void initProgressDialog() { try { if (pd == null) { pd = new NetLoadingDialog(context); pd.setCancelable(cancelable); if (cancelable) { pd.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { if (mProgressCancelListener != null) mProgressCancelListener.onCancelProgress(); } }); } if (!pd.isShowing()) { pd.startAnim(); } } } catch (Exception e) { e.printStackTrace(); } } private void dismissProgressDialog() { if (pd != null) { try { if (pd.isShowing()) { pd.dismiss(); } pd.stopAnim(); pd = null; } catch (Exception e) { e.printStackTrace(); } } } @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PROGRESS_DIALOG: initProgressDialog(); break; case DISMISS_PROGRESS_DIALOG: dismissProgressDialog(); break; } } } app/src/main/java/com/dayu/pipirrapp/net/subscribers/BaseProgressSubscriber.java
New file @@ -0,0 +1,65 @@ package com.dayu.pipirrapp.net.subscribers; import android.content.Context; import androidx.annotation.NonNull; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; /** * Created by zuoxiao on 2017/8/11. */ public abstract class BaseProgressSubscriber<T> implements Observer<T> { public BaseProgressSubscriber() { } @Override public void onSubscribe(@NonNull Disposable d) { onMyStart(d); } // @Override // public void onSubscribe() { // // } @Override public void onComplete() { onMyCompleted(); onCloose(); } @Override public void onError(Throwable e) { onMyError(e); onCloose(); } @Override public void onNext(T t) { onMyNext(t); } public abstract void onMyCompleted(); public abstract void onMyError(Throwable e); public abstract void onMyNext(T t); public abstract void onMyStart(Disposable d); public abstract void onCloose(); public abstract BaseProgressSubscriber iniData(Context context, boolean hideLoading, SubscriberListener<T> mSubscriberListener); public BaseProgressSubscriber initProgressSubscriber(Context context, boolean hideLoading, SubscriberListener<T> mSubscriberListener) { return iniData(context, hideLoading, mSubscriberListener); } } app/src/main/java/com/dayu/pipirrapp/net/subscribers/ProgressSubscriber.java
New file @@ -0,0 +1,131 @@ package com.dayu.pipirrapp.net.subscribers; import android.content.Context; import com.dayu.pipirrapp.net.progress.ProgressCancelListener; import com.dayu.pipirrapp.net.progress.ProgressDialogHandler; import io.reactivex.rxjava3.disposables.Disposable; /** * Created by qwy on 16/3/10. * 用于在Http请求开始时,自动显示一个ProgressDialog * 在Http请求结束是,关闭ProgressDialog * 调用者自己对请求数据进行处理 */ public class ProgressSubscriber<T> extends BaseProgressSubscriber<T> implements ProgressCancelListener { private SubscriberListener mSubscriberListener; private ProgressDialogHandler mProgressDialogHandler; private boolean hideLoading = false;// 是否隐藏加载框,默认展示 Disposable disposable; private Context context; public ProgressSubscriber() { } public ProgressSubscriber(Context context, SubscriberListener<T> mSubscriberListener) { this.mSubscriberListener = mSubscriberListener; this.context = context; try { mProgressDialogHandler = new ProgressDialogHandler(context, this, true); } catch (Exception e) { } } public ProgressSubscriber(Context context, boolean hideLoading, SubscriberListener<T> mSubscriberListener) { this(context, mSubscriberListener); this.hideLoading = hideLoading; } @Override public ProgressSubscriber iniData(Context context, boolean hideLoading, SubscriberListener<T> mSubscriberListener) { return new ProgressSubscriber(context, hideLoading, mSubscriberListener); } private void showProgressDialog() { if (mProgressDialogHandler != null && !hideLoading) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } public void dismissProgressDialog() { try { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget(); mProgressDialogHandler = null; } } catch (Exception e) { e.printStackTrace(); } } /** * 订阅开始时调用 * 显示ProgressDialog */ @Override public void onMyStart(Disposable d) { if (mSubscriberListener != null) { mSubscriberListener.onStart(); } disposable=d; showProgressDialog(); } @Override public void onCloose() { mSubscriberListener.onCloose(); } /** * 完成,隐藏ProgressDialog */ @Override public void onMyCompleted() { if (mSubscriberListener != null) { mSubscriberListener.onCompleted(); } dismissProgressDialog(); } /** * 对错误进行统一处理 * 隐藏ProgressDialog * * @param e */ @Override public void onMyError(Throwable e) { if (mSubscriberListener != null) { mSubscriberListener.onError(e); } dismissProgressDialog(); } /** * 将onNext方法中的返回结果交给Activity或Fragment自己处理 * * @param t 创建Subscriber时的泛型类型 */ @Override public void onMyNext(T t) { if (mSubscriberListener != null) { mSubscriberListener.onNext(t); } } /** * 取消ProgressDialog的时候,取消对observable的订阅,同时也取消了http请求 */ @Override public void onCancelProgress() { if (!disposable.isDisposed()) { disposable.dispose(); } } } app/src/main/java/com/dayu/pipirrapp/net/subscribers/SubscriberListener.java
New file @@ -0,0 +1,24 @@ package com.dayu.pipirrapp.net.subscribers; /** * Created by qwy on 16/3/10. * 监听器 */ public abstract class SubscriberListener<BaseResponse> { public abstract void onNext(BaseResponse t); public void onCompleted() { } public void onStart() { } public void onError(Throwable e) { } public void onCloose(){ } } app/src/main/java/com/dayu/pipirrapp/service/PushService.java
New file @@ -0,0 +1,19 @@ package com.dayu.pipirrapp.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import androidx.annotation.Nullable; import cn.jpush.android.service.JPushMessageService; /** * author: zuo * Date: 2023-12-28 * Time: 10:29 * 备注:推送的服务 */ public class PushService extends JPushMessageService { } app/src/main/res/layout/activity_main.xml
@@ -27,20 +27,20 @@ app:tabSelectedTextColor="#FFC107" app:tabTextColor="#000000"> <com.google.android.material.tabs.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="首页" /> <!-- <com.google.android.material.tabs.TabItem--> <!-- android:layout_width="match_parent"--> <!-- android:layout_height="match_parent"--> <!-- android:text="首页" />--> <com.google.android.material.tabs.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="地图" /> <!-- <com.google.android.material.tabs.TabItem--> <!-- android:layout_width="match_parent"--> <!-- android:layout_height="match_parent"--> <!-- android:text="地图" />--> <com.google.android.material.tabs.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="我的" /> <!-- <com.google.android.material.tabs.TabItem--> <!-- android:layout_width="match_parent"--> <!-- android:layout_height="match_parent"--> <!-- android:text="我的" />--> </com.google.android.material.tabs.TabLayout> </RelativeLayout> app/src/main/res/layout/net_loding.xml
New file @@ -0,0 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <com.pnikosis.materialishprogress.ProgressWheel android:id="@+id/progress_wheel" android:layout_width="80dp" android:layout_height="80dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" app:matProg_barColor="@color/title_color" app:matProg_progressIndeterminate="true" /> </LinearLayout> app/src/main/res/values/colors.xml
@@ -4,4 +4,5 @@ <color name="white">#FFFFFFFF</color> <color name="base_blue">#3C9CFF</color> <color name="down_blue">#0C2DEA</color> <color name="ws_pay_alpha">#00000000</color> </resources> app/src/main/res/values/styles.xml
New file @@ -0,0 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <style name="ws_pay_showSelfDialog" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <item name="android:windowBackground">@color/ws_pay_alpha</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowSoftInputMode">adjustPan</item> </style> </resources> build.gradle
@@ -3,10 +3,12 @@ repositories { google() mavenCentral() maven { url 'https://developer.huawei.com/repo/' } } dependencies { classpath "com.android.tools.build:gradle:8.1.2" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20" classpath 'com.huawei.agconnect:agcp:1.6.0.300' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -19,6 +21,7 @@ mavenCentral() jcenter() // Warning: this repository is going to shut down soon maven {url 'https://www.jitpack.io'} maven { url 'https://developer.huawei.com/repo/' } } }