diff --git a/app/build.gradle b/app/build.gradle index f5bb2e0..10d3ece 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,7 +50,7 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } - viewBinding{ + viewBinding { enabled = true } @@ -142,14 +142,18 @@ dependencies { //okhttp implementation 'com.squareup.okhttp3:okhttp:4.9.3' + //log打印 implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0' //Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' + implementation 'com.squareup.retrofit2:converter-moshi:2.9.0' // gson converter implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 标准转换器,去掉 Retrofit以Mutipart上传参数时,String参数会多一对双引号 implementation 'com.squareup.retrofit2:converter-scalars:2.3.0' + + //RxJava implementation 'io.reactivex.rxjava3:rxjava:3.0.0' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' @@ -189,6 +193,8 @@ dependencies { implementation 'com.gitee.zackratos:UltimateBarX:0.8.0' // //验证码输入 // implementation 'com.jacktuotuo.customview:verificationcodeview:1.0.5' - //动态权限框架 -// implementation 'com.hjq:xxpermissions:6.0' + // 权限请求框架:https://github.com/getActivity/XXPermissions + implementation 'com.github.getActivity:XXPermissions:18.63' + // 吐司框架: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 1a9b385..8991fd3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,15 +6,16 @@ @@ -23,6 +24,13 @@ + + + + android:value="1080" /> + android:value="1920" /> \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/template/activity/main/MainActivity.java b/app/src/main/java/com/ttstd/template/activity/main/MainActivity.java index aa1f984..8514fb1 100644 --- a/app/src/main/java/com/ttstd/template/activity/main/MainActivity.java +++ b/app/src/main/java/com/ttstd/template/activity/main/MainActivity.java @@ -1,10 +1,22 @@ package com.ttstd.template.activity.main; +import android.content.Intent; +import android.view.View; +import android.widget.Button; + import com.ttstd.template.R; +import com.ttstd.template.activity.template.mvp.TemplateActivity; +import com.ttstd.template.activity.template.mvvm.MvvmActivity; import com.ttstd.template.base.BaseActivity; -public class MainActivity extends BaseActivity { +import butterknife.BindView; +import butterknife.ButterKnife; +public class MainActivity extends BaseActivity { + @BindView(R.id.bt_mvp) + Button bt_mvp; + @BindView(R.id.bt_mvvm) + Button bt_mvvm; @Override public int getLayoutId() { @@ -12,8 +24,30 @@ public class MainActivity extends BaseActivity { } @Override - public void initView() { + protected boolean setNightMode() { + return true; + } + @Override + protected boolean setfitWindow() { + return true; + } + + @Override + public void initView() { + ButterKnife.bind(this); + bt_mvp.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(MainActivity.this, TemplateActivity.class)); + } + }); + bt_mvvm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(MainActivity.this, MvvmActivity.class)); + } + }); } @Override diff --git a/app/src/main/java/com/ttstd/template/activity/template/TemplateActivity.java b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateActivity.java similarity index 64% rename from app/src/main/java/com/ttstd/template/activity/template/TemplateActivity.java rename to app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateActivity.java index 6b86678..4335123 100644 --- a/app/src/main/java/com/ttstd/template/activity/template/TemplateActivity.java +++ b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateActivity.java @@ -1,30 +1,39 @@ -package com.ttstd.template.activity.template; +package com.ttstd.template.activity.template.mvp; import android.content.res.Configuration; import androidx.annotation.NonNull; import com.ttstd.template.R; -import com.ttstd.template.base.BaseLightActivity; +import com.ttstd.template.base.mvp.BaseMvpActivity; import butterknife.ButterKnife; -public class TemplateActivity extends BaseLightActivity implements TemplateContact.TemplateView { - +public class TemplateActivity extends BaseMvpActivity implements TemplateContact.TemplateView { private static final String TAG = TemplateActivity.class.getSimpleName(); private TemplatePresenter mPresenter; @Override public int getLayoutId() { - return R.layout.activity_video; + return R.layout.activity_main; + } + + @Override + protected boolean setNightMode() { + return false; + } + + @Override + protected boolean setfitWindow() { + return false; } @Override public void initView() { ButterKnife.bind(this); mPresenter = new TemplatePresenter(this); - mPresenter.setLifecycle(lifecycleSubject); + mPresenter.setLifecycle(getLifecycleSubject()); mPresenter.attachView(this); } diff --git a/app/src/main/java/com/ttstd/template/activity/template/TemplateContact.java b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateContact.java similarity index 53% rename from app/src/main/java/com/ttstd/template/activity/template/TemplateContact.java rename to app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateContact.java index 14e64e3..1def681 100644 --- a/app/src/main/java/com/ttstd/template/activity/template/TemplateContact.java +++ b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplateContact.java @@ -1,7 +1,7 @@ -package com.ttstd.template.activity.template; +package com.ttstd.template.activity.template.mvp; -import com.ttstd.template.base.BasePresenter; -import com.ttstd.template.base.BaseView; +import com.ttstd.template.base.mvp.BasePresenter; +import com.ttstd.template.base.mvp.BaseView; public class TemplateContact { interface Presenter extends BasePresenter { diff --git a/app/src/main/java/com/ttstd/template/activity/template/TemplatePresenter.java b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplatePresenter.java similarity index 95% rename from app/src/main/java/com/ttstd/template/activity/template/TemplatePresenter.java rename to app/src/main/java/com/ttstd/template/activity/template/mvp/TemplatePresenter.java index 96c294c..dee4e86 100644 --- a/app/src/main/java/com/ttstd/template/activity/template/TemplatePresenter.java +++ b/app/src/main/java/com/ttstd/template/activity/template/mvp/TemplatePresenter.java @@ -1,4 +1,4 @@ -package com.ttstd.template.activity.template; +package com.ttstd.template.activity.template.mvp; import android.content.Context; diff --git a/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmActivity.java b/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmActivity.java new file mode 100644 index 0000000..42286a4 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmActivity.java @@ -0,0 +1,55 @@ +package com.ttstd.template.activity.template.mvvm; + +import android.util.Log; + +import androidx.lifecycle.Observer; + +import com.ttstd.template.R; +import com.ttstd.template.base.mvvm.BaseMvvmActivity; +import com.ttstd.template.databinding.ActivityMvvmBinding; + +public class MvvmActivity extends BaseMvvmActivity { + private static final String TAG = MvvmActivity.class.getSimpleName(); + + @Override + protected int getLayoutId() { + return R.layout.activity_mvvm; + } + + @Override + protected boolean setNightMode() { + return true; + } + + @Override + protected boolean setfitWindow() { + return true; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + + mViewModel.getData().observe(this, new Observer() { + @Override + public void onChanged(String s) { + Log.e(TAG, "onChanged: " + s); + } + }); + } + + @Override + protected void initView() { + + } + + @Override + protected void initData() { + mViewModel.setData("mvvm"); + mViewModel.getIp(); + } + + +} diff --git a/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmViewModel.java b/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmViewModel.java new file mode 100644 index 0000000..38ca9cb --- /dev/null +++ b/app/src/main/java/com/ttstd/template/activity/template/mvvm/MvvmViewModel.java @@ -0,0 +1,43 @@ +package com.ttstd.template.activity.template.mvvm; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.ttstd.template.base.mvvm.BaseViewModel; +import com.ttstd.template.databinding.ActivityMvvmBinding; +import com.ttstd.template.network.NetInterfaceManager; + +public class MvvmViewModel extends BaseViewModel { + private static final String TAG = MvvmViewModel.class.getSimpleName(); + + @Override + public void onDestroy() { + + } + + @Override + public ActivityMvvmBinding getVDBinding() { + return binding; + } + + private MutableLiveData mData = new MutableLiveData<>(); + + public MutableLiveData getData() { + return mData; + } + + public void setData(String s) { + mData.setValue(s); + mData.postValue(s); + } + + public void getIp() { + NetInterfaceManager.getInstance().getPublicIp(getLifecycle(), new NetInterfaceManager.PublicIpCallbak() { + @Override + public void getPublicIp(String ip) { + Log.e(TAG, "getPublicIp: " + ip); + } + }); + } +} diff --git a/app/src/main/java/com/ttstd/template/base/BaseActivity.java b/app/src/main/java/com/ttstd/template/base/BaseActivity.java index cde9933..bf442c2 100644 --- a/app/src/main/java/com/ttstd/template/base/BaseActivity.java +++ b/app/src/main/java/com/ttstd/template/base/BaseActivity.java @@ -1,134 +1,32 @@ package com.ttstd.template.base; -import android.app.ActivityManager; -import android.os.Build; import android.os.Bundle; import androidx.annotation.CallSuper; -import androidx.annotation.CheckResult; -import androidx.annotation.ContentView; -import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import com.trello.rxlifecycle4.LifecycleProvider; -import com.trello.rxlifecycle4.LifecycleTransformer; -import com.trello.rxlifecycle4.RxLifecycle; -import com.trello.rxlifecycle4.android.ActivityEvent; -import com.trello.rxlifecycle4.android.RxLifecycleAndroid; -import com.ttstd.template.R; -import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; - -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.subjects.BehaviorSubject; - - -public abstract class BaseActivity extends AppCompatActivity implements LifecycleProvider { - public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); -// StatusBarUtil.init(this); - UltimateBarX.statusBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - UltimateBarX.navigationBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - setContentView(this.getLayoutId()); - initView(); - initData(); - //最近任务和应用图标不一样 - if (Build.VERSION.SDK_INT > 27) { - ActivityManager.TaskDescription description = new ActivityManager.TaskDescription(getString(R.string.app_name), R.mipmap.ic_launcher, getColor(R.color.colorPrimary)); - this.setTaskDescription(description); - } - } - - /** - * 设置布局 - */ - public abstract int getLayoutId(); - - /** - * 初始化视图 - */ - public abstract void initView(); - - - /** - * 初始化数据 - */ - public abstract void initData(); +public abstract class BaseActivity extends BaseTransparentActivity { public BaseActivity() { super(); } - @ContentView - public BaseActivity(@LayoutRes int contentLayoutId) { - super(contentLayoutId); - } - - @Override - @NonNull - @CheckResult - public final Observable lifecycle() { - return lifecycleSubject.hide(); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { - return RxLifecycle.bindUntilEvent(lifecycleSubject, event); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindToLifecycle() { - return RxLifecycleAndroid.bindActivity(lifecycleSubject); - } - @Override @CallSuper - protected void onStart() { - super.onStart(); - lifecycleSubject.onNext(ActivityEvent.START); + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + initView(); + initData(); } - @Override - @CallSuper - protected void onResume() { - super.onResume(); - lifecycleSubject.onNext(ActivityEvent.RESUME); - } + /** + * 初始化视图 + */ + protected abstract void initView(); - @Override - @CallSuper - protected void onPause() { - lifecycleSubject.onNext(ActivityEvent.PAUSE); - super.onPause(); - } - - @Override - @CallSuper - protected void onStop() { - lifecycleSubject.onNext(ActivityEvent.STOP); - super.onStop(); - } - - @Override - @CallSuper - protected void onDestroy() { - lifecycleSubject.onNext(ActivityEvent.DESTROY); - super.onDestroy(); - } -} + /** + * 初始化数据 + */ + protected abstract void initData(); +} \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/template/base/BaseDataBindingActivity.java b/app/src/main/java/com/ttstd/template/base/BaseDataBindingActivity.java new file mode 100644 index 0000000..82f121a --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/BaseDataBindingActivity.java @@ -0,0 +1,62 @@ +package com.ttstd.template.base; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; + +import com.ttstd.template.R; +import com.ttstd.template.base.rx.BaseRxActivity; +import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; + +public abstract class BaseDataBindingActivity extends BaseRxActivity { + + public BaseDataBindingActivity() { + super(); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +// StatusBarUtil.init(this); + UltimateBarX.statusBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(setfitWindow()) + .apply(); + UltimateBarX.navigationBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(setfitWindow()) + .apply(); + initDataBinding(); + initView(); + initData(); + } + + /** + * @return 是否是黑色状态栏 + */ + protected abstract boolean setNightMode(); + + /** + * @return 是否是入侵 + */ + protected abstract boolean setfitWindow(); + + + protected abstract void initDataBinding(); + + /** + * 初始化视图 + */ + protected abstract void initView(); + + /** + * 初始化数据 + */ + protected abstract void initData(); +} \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/template/base/BaseFragment.java b/app/src/main/java/com/ttstd/template/base/BaseFragment.java index 629b500..1ebbe59 100644 --- a/app/src/main/java/com/ttstd/template/base/BaseFragment.java +++ b/app/src/main/java/com/ttstd/template/base/BaseFragment.java @@ -1,72 +1,15 @@ package com.ttstd.template.base; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import androidx.annotation.CallSuper; -import androidx.annotation.CheckResult; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; +import com.ttstd.template.base.rx.BaseRxFragment; -import com.trello.rxlifecycle4.LifecycleProvider; -import com.trello.rxlifecycle4.LifecycleTransformer; -import com.trello.rxlifecycle4.RxLifecycle; -import com.trello.rxlifecycle4.android.FragmentEvent; -import com.trello.rxlifecycle4.android.RxLifecycleAndroid; - -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.subjects.BehaviorSubject; - -public abstract class BaseFragment extends Fragment implements LifecycleProvider { - public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); +public abstract class BaseFragment extends BaseRxFragment { protected boolean isViewInitiated; protected boolean isVisibleToUser; protected boolean isDataInitiated; - @Override - @NonNull - @CheckResult - public final Observable lifecycle() { - return lifecycleSubject.hide(); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { - return RxLifecycle.bindUntilEvent(lifecycleSubject, event); - } - - @Override - @NonNull - @CheckResult - public final LifecycleTransformer bindToLifecycle() { - return RxLifecycleAndroid.bindFragment(lifecycleSubject); - } - - @Override - @CallSuper - public void onAttach(android.app.Activity activity) { - super.onAttach(activity); - lifecycleSubject.onNext(FragmentEvent.ATTACH); - } - - @Override - @CallSuper - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - lifecycleSubject.onNext(FragmentEvent.CREATE); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return super.onCreateView(inflater, container, savedInstanceState); - } @Override public void onActivityCreated(Bundle savedInstanceState) { @@ -92,65 +35,10 @@ public abstract class BaseFragment extends Fragment implements LifecycleProvider if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) { fetchData(); //注释掉保证每次都更新数据 - isDataInitiated = true; +// isDataInitiated = true; return true; } return false; } - @Override - @CallSuper - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); - } - - @Override - @CallSuper - public void onStart() { - super.onStart(); - lifecycleSubject.onNext(FragmentEvent.START); - } - - @Override - @CallSuper - public void onResume() { - super.onResume(); - lifecycleSubject.onNext(FragmentEvent.RESUME); - } - - @Override - @CallSuper - public void onPause() { - lifecycleSubject.onNext(FragmentEvent.PAUSE); - super.onPause(); - } - - @Override - @CallSuper - public void onStop() { - lifecycleSubject.onNext(FragmentEvent.STOP); - super.onStop(); - } - - @Override - @CallSuper - public void onDestroyView() { - lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); - super.onDestroyView(); - } - - @Override - @CallSuper - public void onDestroy() { - lifecycleSubject.onNext(FragmentEvent.DESTROY); - super.onDestroy(); - } - - @Override - @CallSuper - public void onDetach() { - lifecycleSubject.onNext(FragmentEvent.DETACH); - super.onDetach(); - } } diff --git a/app/src/main/java/com/ttstd/template/base/BaseMvvmFragment.java b/app/src/main/java/com/ttstd/template/base/BaseMvvmFragment.java new file mode 100644 index 0000000..667fbe9 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/BaseMvvmFragment.java @@ -0,0 +1,273 @@ +package com.ttstd.template.base; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import java.lang.ref.WeakReference; +import java.lang.reflect.ParameterizedType; + +/** + * @author: lml + * @date: 2021/12/15 + */ +public abstract class BaseMvvmFragment extends BaseFragment { + protected String mTag = this.getClass().getSimpleName(); + /** + * 是否顯示了 + */ + protected boolean mIsVisible; + /** + * 是否準備好了-Created + */ + protected boolean mHasPrepare; + + + protected VM mViewModel; + protected VDB mViewDataBinding; + protected Class vmClass; + // +// protected Toolbar toolbar; +// protected View statusBarView; + // + protected Bundle bundle;//来自getArguments() + protected Bundle savedInstanceState; + +// protected Context context; + + /** + * 上下文 + */ + private WeakReference ctx; + + public Context getCtx() { + return ctx == null ? null : ctx.get(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); +// this.context = context; + ctx = new WeakReference<>(context); + } + + /** + * onCreate、onResume里不能调用 + * + * @return + */ + public boolean isAttached() { + boolean flag = getCtx() != null && isAdded(); + Log.e(" >> isAttached >>", "flag = " + flag); + return flag; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + //ViewDataBinding + mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false); + mViewDataBinding.setLifecycleOwner(this); + + //ViewModel + vmClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + mViewModel = new ViewModelProvider(this).get(vmClass); + // + return mViewDataBinding.getRoot(); + } + + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + +// if (initStatusBarToolBar()) { +// toolbar = getToolbar(); +// } + //注册eventbus +// if (getClass().isAnnotationPresent(BindEventBus.class)) +// EventBusManager.register(this); + // + +// fitsLayoutOverlap(); + initDataBinding(); + initView(bundle = getArguments()); + // + initData(this.savedInstanceState = savedInstanceState); + // + if (mIsVisible) { + onEnter(); + } + mHasPrepare = true; + // +// LiveDataBus.get().with(ConstantUtils.DATA_BUS_LOADING_FRAGMENT, Boolean.class).observe(getActivity(), bool -> { +// L.e(" >> LiveDataBus >> DATA_BUS_LOADING_FRAGMENT: %s", bool); +// if(bool) { +// showLoading(R.string.str_please_wait); +// } else { +// hideLoading(); +// } +// }); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mHasPrepare = false; + mViewDataBinding = null; + //移除eventbus +// if (getClass().isAnnotationPresent(BindEventBus.class)) +// EventBusManager.unregister(this); + // + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (mIsVisible == getUserVisibleHint()) + return; + mIsVisible = getUserVisibleHint(); + if (mIsVisible) { + if (!mHasPrepare) + return; + onEnter(); + } else { + onExit(); + } + } + + @LayoutRes + protected abstract int getLayoutId(); + +// protected abstract Toolbar getToolbar(); + +// protected View getStatusView() { +// return null; +// } + + protected abstract void initDataBinding(); + + protected abstract void initView(Bundle bundle); + + protected abstract void initData(Bundle savedInstanceState); + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); +// fitsLayoutOverlap(); + } + +// protected boolean isImmersionBarEnabled() { +// return true; +// } + +// protected boolean initStatusBarToolBar() { +// return true; +// } + + +// private void fitsLayoutOverlap() { +// if (!isImmersionBarEnabled()) return; +// if (statusBarView != null) { +// ImmersionBar.setStatusBarView(getActivity(), statusBarView); +// } +// if (toolbar != null) { +// ImmersionBar.setTitleBar(getActivity(), toolbar); +// } +// } + + protected void hideInputMethod(Activity activity) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + View view = activity.getCurrentFocus(); + if (view != null) { + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + protected void hideInputMethod(Activity activity, EditText editText) { + InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); + View view = activity.getCurrentFocus(); + if (view != null) { + imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + protected void showInputMethod(EditText editText) { + InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED); + } + + +// private CustomDialog mWaitDialog; +// +// public void showLoading(@StringRes int contentID) { +// showLoading(contentID, R.color.white); +// } +// +// public void showLoading(@StringRes int contentID, @ColorRes int color) { +// hideLoading(); +// DialogX.init(getActivity()); +// if (color == R.color.white) { +// mWaitDialog = DialogXUtil.getInstance().showLoading(getActivity(), getString(contentID), getResources().getColor(color)); +// } else { +// mWaitDialog = DialogXUtil.getInstance().showLoading_black(getActivity(), getString(contentID), getResources().getColor(color)); +// } +// } +// +// public void updateLoadingTip(@StringRes int messageID, int percent) { +// try { +// if (mWaitDialog != null && mWaitDialog.isShow()) { +// TextView tvTip = mWaitDialog.getCustomView().findViewById(R.id.tv_load_tip); +// if (tvTip != null) +// tvTip.setText(getResources().getString(messageID) + (percent == -1 ? "" : percent + "%")); +// } +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// +// public boolean isShowLoading() { +// return mWaitDialog != null && mWaitDialog.isShow(); +// } +// +// public void hideLoading() { +// try { +// boolean isShow = isShowLoading(); +// L.d(" >> hideLoading :: isShow: %s", isShow); +// if (isShow) +// mWaitDialog.dismiss(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } + + /** + * 進入界面 + */ + protected void onEnter() { + + } + + /** + * 離開界面 + */ + protected void onExit() { + + } + +} diff --git a/app/src/main/java/com/ttstd/template/base/BaseService.java b/app/src/main/java/com/ttstd/template/base/BaseService.java new file mode 100644 index 0000000..7b0ca76 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/BaseService.java @@ -0,0 +1,56 @@ +package com.ttstd.template.base; + +import android.app.Service; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + + +public abstract class BaseService extends Service implements LifecycleProvider { + public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BaseService() { + super(); + } + + @Override + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleSubject.onNext(ActivityEvent.STOP); + } +} diff --git a/app/src/main/java/com/ttstd/template/base/BaseTransparentActivity.java b/app/src/main/java/com/ttstd/template/base/BaseTransparentActivity.java new file mode 100644 index 0000000..d3b7abb --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/BaseTransparentActivity.java @@ -0,0 +1,51 @@ +package com.ttstd.template.base; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; + +import com.ttstd.template.R; +import com.ttstd.template.base.rx.BaseRxActivity; +import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; + +public abstract class BaseTransparentActivity extends BaseRxActivity { + + public BaseTransparentActivity() { + super(); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +// StatusBarUtil.init(this); + UltimateBarX.statusBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(setfitWindow()) + .apply(); + UltimateBarX.navigationBar(this) + .transparent() + .colorRes(R.color.colorPrimaryDark) + .light(setNightMode()) + .fitWindow(setfitWindow()) + .apply(); + } + + /** + * 设置布局 + */ + protected abstract int getLayoutId(); + + /** + * @return 是否是黑色状态栏 + */ + protected abstract boolean setNightMode(); + + /** + * @return 是否是入侵 + */ + protected abstract boolean setfitWindow(); +} \ No newline at end of file diff --git a/app/src/main/java/com/ttstd/template/base/BaseView.java b/app/src/main/java/com/ttstd/template/base/BaseView.java deleted file mode 100644 index 75bcf3f..0000000 --- a/app/src/main/java/com/ttstd/template/base/BaseView.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.ttstd.template.base; - -public interface BaseView { -} diff --git a/app/src/main/java/com/ttstd/template/base/mvp/BaseMvpActivity.java b/app/src/main/java/com/ttstd/template/base/mvp/BaseMvpActivity.java new file mode 100644 index 0000000..c783afe --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/mvp/BaseMvpActivity.java @@ -0,0 +1,34 @@ +package com.ttstd.template.base.mvp; + +import android.os.Bundle; + +import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; + +import com.ttstd.template.base.BaseTransparentActivity; + +public abstract class BaseMvpActivity extends BaseTransparentActivity { + + public BaseMvpActivity() { + super(); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + initView(); + initData(); + } + + /** + * 初始化视图 + */ + protected abstract void initView(); + + /** + * 初始化数据 + */ + protected abstract void initData(); +} diff --git a/app/src/main/java/com/ttstd/template/base/BasePresenter.java b/app/src/main/java/com/ttstd/template/base/mvp/BasePresenter.java similarity index 74% rename from app/src/main/java/com/ttstd/template/base/BasePresenter.java rename to app/src/main/java/com/ttstd/template/base/mvp/BasePresenter.java index 8e81b2a..fe69fdd 100644 --- a/app/src/main/java/com/ttstd/template/base/BasePresenter.java +++ b/app/src/main/java/com/ttstd/template/base/mvp/BasePresenter.java @@ -1,4 +1,4 @@ -package com.ttstd.template.base; +package com.ttstd.template.base.mvp; public interface BasePresenter { void attachView(V view); diff --git a/app/src/main/java/com/ttstd/template/base/mvp/BaseView.java b/app/src/main/java/com/ttstd/template/base/mvp/BaseView.java new file mode 100644 index 0000000..0f3b988 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/mvp/BaseView.java @@ -0,0 +1,4 @@ +package com.ttstd.template.base.mvp; + +public interface BaseView { +} diff --git a/app/src/main/java/com/ttstd/template/base/mvvm/BaseMvvmActivity.java b/app/src/main/java/com/ttstd/template/base/mvvm/BaseMvvmActivity.java new file mode 100644 index 0000000..3b3e9b5 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/mvvm/BaseMvvmActivity.java @@ -0,0 +1,55 @@ +package com.ttstd.template.base.mvvm; + +import android.os.Bundle; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + + +import com.ttstd.template.base.BaseTransparentActivity; + +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; + +public abstract class BaseMvvmActivity extends BaseTransparentActivity { + + private static final String TAG = BaseMvvmActivity.class.getSimpleName(); + + protected VM mViewModel; + protected VDB mViewDataBinding; + protected Class vmClass; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //ViewDataBinding + mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId()); + mViewDataBinding.setLifecycleOwner(this); + //ViewModel + vmClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers()); + Log.e(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract); + if (!isAbstract) {//不是一个抽象类 + mViewModel = new ViewModelProvider(this).get(vmClass); + } + initDataBinding(); + initView(); + initData(); + } + + protected abstract void initDataBinding(); + + /** + * 初始化视图 + */ + protected abstract void initView(); + + /** + * 初始化数据 + */ + protected abstract void initData(); +} diff --git a/app/src/main/java/com/ttstd/template/base/mvvm/BaseViewModel.java b/app/src/main/java/com/ttstd/template/base/mvvm/BaseViewModel.java new file mode 100644 index 0000000..af12866 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/mvvm/BaseViewModel.java @@ -0,0 +1,73 @@ +package com.ttstd.template.base.mvvm; + +import android.content.Context; + +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; + +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.lang.ref.WeakReference; + +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * 所有viewmodel的基类 + */ +public abstract class BaseViewModel extends ViewModel implements ViewDataBindingCallback { + + /** + * 当前viewmodel对应的页面binding + */ + protected VDB binding; + + @Override + public void setVDBinding(ViewDataBinding vdBinding) { + + binding = (VDB)vdBinding; + } + + @Override + public VDB getVDBinding() { + if (binding == null) { + throw new NullPointerException("BaseViewModel >> getVDBinding >> null!!!"); + } + return binding; + } + + + /** + * 上下文 + */ + private WeakReference ctx; + + @Override + public void setCtx(Context context) { + if(ctx == null) { + ctx = new WeakReference<>(context); + } + } + + @Override + public Context getCtx() { + if (ctx == null) { + throw new NullPointerException("BaseViewModel >> getCtx >> null!!!"); + } + return ctx.get(); + } + + + public abstract void onDestroy(); + + private BehaviorSubject mBehaviorSubject; + + @Override + public void setLifecycle(BehaviorSubject subject) { + this.mBehaviorSubject =subject; + } + + @Override + public BehaviorSubject getLifecycle() { + return mBehaviorSubject; + } +} diff --git a/app/src/main/java/com/ttstd/template/base/mvvm/ViewDataBindingCallback.java b/app/src/main/java/com/ttstd/template/base/mvvm/ViewDataBindingCallback.java new file mode 100644 index 0000000..dd37308 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/mvvm/ViewDataBindingCallback.java @@ -0,0 +1,26 @@ +package com.ttstd.template.base.mvvm; + +import android.content.Context; + +import androidx.databinding.ViewDataBinding; + +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public interface ViewDataBindingCallback { + + + void setVDBinding(VDB binding); + + VDB getVDBinding() throws NullPointerException; + + + void setCtx(Context context); + + Context getCtx() throws NullPointerException; + + void setLifecycle(BehaviorSubject subject); + + BehaviorSubject getLifecycle(); +} diff --git a/app/src/main/java/com/ttstd/template/base/BaseLightActivity.java b/app/src/main/java/com/ttstd/template/base/rx/BaseRxActivity.java similarity index 61% rename from app/src/main/java/com/ttstd/template/base/BaseLightActivity.java rename to app/src/main/java/com/ttstd/template/base/rx/BaseRxActivity.java index 6ec1beb..4006b91 100644 --- a/app/src/main/java/com/ttstd/template/base/BaseLightActivity.java +++ b/app/src/main/java/com/ttstd/template/base/rx/BaseRxActivity.java @@ -1,11 +1,9 @@ -package com.ttstd.template.base; +package com.ttstd.template.base.rx; import android.os.Bundle; import androidx.annotation.CallSuper; import androidx.annotation.CheckResult; -import androidx.annotation.ContentView; -import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -15,23 +13,19 @@ import com.trello.rxlifecycle4.LifecycleTransformer; import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.trello.rxlifecycle4.android.RxLifecycleAndroid; -import com.ttstd.template.R; -import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.BehaviorSubject; +/** + * {@link com.trello.rxlifecycle4.components.RxActivity} + * copied form RxActivity} + */ +public abstract class BaseRxActivity extends AppCompatActivity implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); -public abstract class BaseLightActivity extends AppCompatActivity implements LifecycleProvider { - public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); - - public BaseLightActivity() { - super(); - } - - @ContentView - public BaseLightActivity(@LayoutRes int contentLayoutId) { - super(contentLayoutId); + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; } @Override @@ -60,38 +54,8 @@ public abstract class BaseLightActivity extends AppCompatActivity implements Lif protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleSubject.onNext(ActivityEvent.CREATE); -// StatusBarUtil.init(this); - UltimateBarX.statusBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - UltimateBarX.navigationBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) - .apply(); - setContentView(this.getLayoutId()); - initView(); - initData(); } - /** - * 设置布局 - */ - public abstract int getLayoutId(); - - /** - * 初始化视图 - */ - public abstract void initView(); - - - /** - * 初始化数据 - */ - public abstract void initData(); - @Override @CallSuper protected void onStart() { @@ -127,3 +91,4 @@ public abstract class BaseLightActivity extends AppCompatActivity implements Lif super.onDestroy(); } } + diff --git a/app/src/main/java/com/ttstd/template/base/rx/BaseRxFragment.java b/app/src/main/java/com/ttstd/template/base/rx/BaseRxFragment.java new file mode 100644 index 0000000..562181c --- /dev/null +++ b/app/src/main/java/com/ttstd/template/base/rx/BaseRxFragment.java @@ -0,0 +1,123 @@ +package com.ttstd.template.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxFragment extends Fragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/app/src/main/java/com/ttstd/template/bean/WhoisBean.java b/app/src/main/java/com/ttstd/template/bean/WhoisBean.java new file mode 100644 index 0000000..ca9d64c --- /dev/null +++ b/app/src/main/java/com/ttstd/template/bean/WhoisBean.java @@ -0,0 +1,109 @@ +package com.ttstd.template.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class WhoisBean implements Serializable { + private static final long serialVersionUID = -6537021620041268080L; + + String ip; + String pro; + String proCode; + String city; + String cityCode; + String region; + String regionCode; + String addr; + String regionNames; + String err; + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getPro() { + return pro; + } + + public void setPro(String pro) { + this.pro = pro; + } + + public String getProCode() { + return proCode; + } + + public void setProCode(String proCode) { + this.proCode = proCode; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getRegionCode() { + return regionCode; + } + + public void setRegionCode(String regionCode) { + this.regionCode = regionCode; + } + + public String getAddr() { + return addr; + } + + public void setAddr(String addr) { + this.addr = addr; + } + + public String getRegionNames() { + return regionNames; + } + + public void setRegionNames(String regionNames) { + this.regionNames = regionNames; + } + + public String getErr() { + return err; + } + + public void setErr(String err) { + this.err = err; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/app/src/main/java/com/ttstd/template/network/NetInterfaceManager.java b/app/src/main/java/com/ttstd/template/network/NetInterfaceManager.java index 812fbfc..b19d105 100644 --- a/app/src/main/java/com/ttstd/template/network/NetInterfaceManager.java +++ b/app/src/main/java/com/ttstd/template/network/NetInterfaceManager.java @@ -4,19 +4,33 @@ import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.os.Environment; +import android.text.TextUtils; +import android.util.Log; import com.tencent.mmkv.MMKV; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; import com.ttstd.template.bean.BaseResponse; +import com.ttstd.template.bean.WhoisBean; import com.ttstd.template.comm.CommonConfig; +import com.ttstd.template.network.api.GetWhoisApi; import com.ttstd.template.network.interceptor.RepeatRequestInterceptor; +import org.jetbrains.annotations.NotNull; + import java.io.File; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.BehaviorSubject; import okhttp3.Cache; import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; @@ -57,7 +71,12 @@ public class NetInterfaceManager { builder.readTimeout(timeOut, TimeUnit.SECONDS);// 设置读取数据超时时间 builder.retryOnConnectionFailure(true);// 设置进行连接失败重试 builder.addInterceptor(new RepeatRequestInterceptor()); - + builder.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { + @Override + public void log(@NotNull String s) { + Log.e("HttpLoggingInterceptor", "log: " + s); + } + }).setLevel(HttpLoggingInterceptor.Level.BASIC)); // 设置缓存文件路径 String cacheDirectory = getCacheDir() + "/OkHttpCache"; Cache cache = new Cache(new File(cacheDirectory), cacheSize); @@ -111,6 +130,9 @@ public class NetInterfaceManager { return okHttpClient; } + public static final String WHOIS_IP = "whois_ip_addr"; + + /* * * Observable @@ -155,4 +177,52 @@ public class NetInterfaceManager { void onComplete(); } + public interface PublicIpCallbak { + void getPublicIp(String ip); + } + + + public void getPublicIp(BehaviorSubject lifecycle, PublicIpCallbak callbak) { + Retrofit retrofit = new Retrofit.Builder() + .client(NetInterfaceManager.getInstance().getOkHttpClient()) + .baseUrl(UrlAddress.PCONLINE_WHOIS) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .build(); + retrofit.create(GetWhoisApi.class) + .getWhois(true) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getPublicIp", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull WhoisBean whoisBean) { + Log.e("getPublicIp", "onNext: " + whoisBean); + if (whoisBean != null && !TextUtils.isEmpty(whoisBean.getIp())) { + callbak.getPublicIp(whoisBean.getIp()); + MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE).encode(WHOIS_IP, whoisBean.getIp()); + } else { + callbak.getPublicIp("unknown"); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getPublicIp", "onError: "); + callbak.getPublicIp("unknown"); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getPublicIp", "onComplete: "); + } + }); + } + } diff --git a/app/src/main/java/com/ttstd/template/network/UrlAddress.java b/app/src/main/java/com/ttstd/template/network/UrlAddress.java index 1089c26..8d7e966 100644 --- a/app/src/main/java/com/ttstd/template/network/UrlAddress.java +++ b/app/src/main/java/com/ttstd/template/network/UrlAddress.java @@ -4,77 +4,7 @@ public class UrlAddress { /*主页接口*/ public static final String ROOT_URL = "https://led.zuoyepad.com/android/"; - /*设备激活*/ - public static final String SN_ACTIVATION = "sn/snActivation"; - /*获取设备是否激活*/ - public static final String GET_SN_IS_ACTIVATION = "sn/getSnIsActivation"; - /*获取设备激活二维码链接*/ - public static final String ACTIVATION_QRCODE = "pay/getActivationQrcode"; - - /*获取文件*/ - public static final String GET_FILES = "file/getFiles"; - /*获取操作指南*/ - public static final String GET_OPERATION_GUIDE = "file/getFiles"; - - - /*上传屏幕截图*/ - public final static String UPLOAD_SCREEN_SNAPSHOT = "sn/uploadScreenshot"; - /*浏览器网址管控*/ - public final static String SET_BROWSER_URL = "control/getBrowser"; - /*浏览器书签管控*/ - public final static String SET_BROWSER_LABEL = "control/getLabel"; - /*上传控制面版截图*/ - public static final String UPLOAD_CONTROL_SCREENSHOT = "sn/uploadControlScreenshot"; - - - /*设备信息接口*/ - public static final String SNINFO = "sn/getSnInfo"; - /*获取用户头像和信息*/ - public static final String GET_USER_AVATAR_INFO = "sn/getUserAvatarInfo"; - /*获取设备类型*/ - public static final String GET_SN_TYPE = "sn/getSnType"; - /*获取正在运行的app*/ - public static final String RUN_NEW_APP = "app/runNewApp"; - /*获取所有应用*/ - public final static String GET_ALL_PACKAGE = "app/queryAllApp"; - /*绑定设备消息*/ - public final static String BIND_DEVICES = "sn/bindSn"; - /*获取系统设置*/ - public final static String GET_SETTINGS = "control/getSetting"; - /*获取强制下载*/ - public final static String GET_FORCE_INSTALL = "app/getForceDownload"; - /*发送卸载或者安装信息*/ - public final static String SEND_INSTALLEDORREMOVED = "app/addAppInstall"; - /*发送设备基本信息*/ - public final static String UPDATE_SNINFO = "sn/updateAdminSn"; - /*根据包名获取更新*/ - public final static String GET_NEWESTAPPUPDATE = "app/newestAppUpdate"; - /*获取禁用包名*/ - public static final String GET_APP_ICON = "getAppIcon"; - /*获取灰度更新*/ - public static final String GET_TEST_APP_INFO = "app/getTestAppInfo"; - /*获取wifi*/ - public static final String GET_WIFI_ALIAS_PW = "getWifi"; - - /*获取屏幕管控*/ - public final static String GET_SCREEN_LOCK = "sn/getScreenshot"; - /*获取锁屏密码*/ - public static final String LOCK_SCREEN_PWD = "sn/getLockScreenPwd"; - /*解除锁屏*/ - public static final String UPDATE_LOCK_SCREEN = "sn/updateLockScreen"; - - /*发送绑定验证码*/ - public static final String SEND_BIND_VER_CODE = "Sn/sendBindVerCode"; - /*手动绑定设备*/ - public static final String EQUIPMENT_BIND = "Sn/equipmentBind"; - - /*上传应用图标*/ - public static final String UPLOAD_APP_IMG = "collectData/uploadAppImg"; - /*获取应用库是否有图标*/ - public static final String GET_IS_APP_IMG = "collectData/getIsAppImg"; - - /*通过ip获取信息*/ - public static final String PCONLINE_WHOIS = "http://whois.pconline.com.cn/"; + public static final String PCONLINE_WHOIS = "https://whois.pconline.com.cn/"; public static final String WHOIS = "ipJson.jsp"; } diff --git a/app/src/main/java/com/ttstd/template/network/api/GetWhoisApi.java b/app/src/main/java/com/ttstd/template/network/api/GetWhoisApi.java new file mode 100644 index 0000000..a790999 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/network/api/GetWhoisApi.java @@ -0,0 +1,22 @@ +package com.ttstd.template.network.api; + +import com.ttstd.template.bean.WhoisBean; +import com.ttstd.template.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +/** + * @author : fanhuitong + * e-mail : + * @date : 2021/10/1814:39 + * desc : + * version: 1.0 + */ +public interface GetWhoisApi { + @GET(UrlAddress.WHOIS) + Observable getWhois( + @Query("json") boolean json + ); +} diff --git a/app/src/main/java/com/ttstd/template/rv/EquallyDividedItemDecoration.java b/app/src/main/java/com/ttstd/template/rv/EquallyDividedItemDecoration.java new file mode 100644 index 0000000..39a72b7 --- /dev/null +++ b/app/src/main/java/com/ttstd/template/rv/EquallyDividedItemDecoration.java @@ -0,0 +1,74 @@ +package com.ttstd.template.rv; + +import android.graphics.Rect; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class EquallyDividedItemDecoration extends RecyclerView.ItemDecoration { + private static final String TAG = EquallyDividedItemDecoration.class.getSimpleName(); + + private int mSpanCount;//横条目数量 + private int mHalfRowSpacing;//行间距的一半 + private int mHalfColumnSpacing;// 列间距的一半 + + + public EquallyDividedItemDecoration(int spanCount, int halfRowSpacing) { + mSpanCount = spanCount; + mHalfRowSpacing = halfRowSpacing; + mHalfColumnSpacing = halfRowSpacing; + } + + public EquallyDividedItemDecoration(int spanCount, int halfRowSpacing, int halfColumnSpacing) { + mSpanCount = spanCount; + mHalfRowSpacing = halfRowSpacing; + mHalfColumnSpacing = halfColumnSpacing; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。 + Log.d(TAG, "getItemOffsets: position = " + position); + + int itemCount = parent.getAdapter().getItemCount();//item全部数量 + Log.d(TAG, "getItemOffsets: itemCount = " + itemCount); + + int column = position % mSpanCount; // view 所在的列 + Log.d(TAG, "getItemOffsets: column = " + column); + + if (column == 0) { + outRect.left = 2 * mHalfRowSpacing; + outRect.right = mHalfRowSpacing; + } else if (column == mSpanCount - 1) { + outRect.left = mHalfRowSpacing; + outRect.right = 2 * mHalfRowSpacing; + } else { + outRect.left = mHalfRowSpacing; + outRect.right = mHalfRowSpacing; + } + + int row = (position / 3);//所在行 + Log.d(TAG, "getItemOffsets: row = " + row); + int maxRow = (int) Math.ceil((double) itemCount / mSpanCount);//一共多少行 + Log.d(TAG, "getItemOffsets: maxRow = " + maxRow); + + if (row == 0) { + outRect.top = 2 * mHalfColumnSpacing; + outRect.bottom = mHalfColumnSpacing; + } else if (row == maxRow - 1) { + outRect.top = mHalfColumnSpacing; + outRect.bottom = 2 * mHalfColumnSpacing; + } else { + outRect.top = mHalfColumnSpacing; + outRect.bottom = mHalfColumnSpacing; + } + + Log.d(TAG, "getItemOffsets: outRect.left = " + outRect.left); + Log.d(TAG, "getItemOffsets: outRect.right = " + outRect.right); + Log.d(TAG, "getItemOffsets: outRect.top = " + outRect.top); + Log.d(TAG, "getItemOffsets: outRect.bottom = " + outRect.bottom); + } +} diff --git a/app/src/main/java/com/ttstd/template/utils/GlideLoadUtils.java b/app/src/main/java/com/ttstd/template/utils/GlideLoadUtils.java new file mode 100644 index 0000000..290793b --- /dev/null +++ b/app/src/main/java/com/ttstd/template/utils/GlideLoadUtils.java @@ -0,0 +1,121 @@ +package com.ttstd.template.utils; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.Log; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; + +/** + * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常 + * Created by Li_Xavier on 2017/6/20 0020. + */ +public class GlideLoadUtils { + private String TAG = "ImageLoader"; + + /** + * 借助内部类 实现线程安全的单例模式 + * 属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInstance() + * 方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的。 + * 内部类加载的时候实例化一次instance。 + */ + public GlideLoadUtils() { + } + + private static class GlideLoadUtilsHolder { + private final static GlideLoadUtils INSTANCE = new GlideLoadUtils(); + } + + public static GlideLoadUtils getInstance() { + return GlideLoadUtilsHolder.INSTANCE; + } + + /** + * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常 + * + * @param context + * @param url 加载图片的url地址 String + * @param imageView 加载图片的ImageView 控件 + * @param default_image 图片展示错误的本地图片 id + */ + public void glideLoad(Context context, String url, ImageView imageView, int default_image) { + if (context != null) { + Glide.with(context).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoadc(Context context, String url, ImageView imageView, Drawable default_image) { + if (context != null) { + Glide.with(context).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Activity activity, String url, ImageView imageView, Drawable drawable) { + if (activity != null && !activity.isDestroyed()) { + Glide.with(activity.getApplicationContext()).load(url).error(drawable).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, String url, ImageView imageView) { + if (context != null) { + Glide.with(context).load(url).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, int drawableId, ImageView imageView) { + if (context != null) { + Glide.with(context).load(context.getDrawable(drawableId)).centerCrop().into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + public void glideLoad(Activity activity, String url, ImageView imageView, int default_image) { + if (!activity.isDestroyed()) { +// Glide.with(activity).load(url).centerCrop().dontAnimate().error(default_image).into(imageView); + Glide.with(activity).load(url).into(new SimpleTarget() { + @Override + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + imageView.setImageDrawable(resource); + } + }); + } else { + Log.i(TAG, "Picture loading failed,activity is Destroyed"); + } + } + + public void glideLoad(Fragment fragment, String url, ImageView imageView, int default_image) { + if (fragment != null && fragment.getActivity() != null) { + Glide.with(fragment).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,fragment is null"); + } + } + + public void glideLoad(android.app.Fragment fragment, String url, ImageView imageView, int default_image) { + if (fragment != null && fragment.getActivity() != null) { + Glide.with(fragment).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,android.app.Fragment is null"); + } + } +} diff --git a/app/src/main/java/com/ttstd/template/view/DataBindingAdapter.java b/app/src/main/java/com/ttstd/template/view/DataBindingAdapter.java new file mode 100644 index 0000000..462376b --- /dev/null +++ b/app/src/main/java/com/ttstd/template/view/DataBindingAdapter.java @@ -0,0 +1,54 @@ +package com.ttstd.template.view; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import androidx.databinding.BindingAdapter; + +import com.bumptech.glide.Glide; +import com.ttstd.template.R; +import com.ttstd.template.utils.GlideLoadUtils; + +public class DataBindingAdapter { + @BindingAdapter("android:src") + public static void setSrc(ImageView view, Bitmap bitmap) { + view.setImageBitmap(bitmap); + } + + @BindingAdapter("android:src") + public static void setSrc(ImageView view, int resId) { + view.setImageResource(resId); + } + + @BindingAdapter("imageUrl") + public static void setSrc(ImageView imageView, String url) { + Glide.with(imageView.getContext()) + .load(url) + .error(R.mipmap.ic_launcher) + .centerCrop() + .into(imageView); + } + + /** + * 自定义设置图片属性 - 在匹配时自定义命名空间会被忽略 + */ + @BindingAdapter({"imageUrl", "error"}) + public static void loadImage(ImageView imageView, String url, Drawable error) { + GlideLoadUtils.getInstance().glideLoadc(imageView.getContext(), url, imageView, error); + } + + @BindingAdapter({"loadUrl"}) + public static void loadUrl(ImageView imageView, String url) { + if (TextUtils.isEmpty(url)) { + imageView.setVisibility(View.GONE); + } else { + imageView.setVisibility(View.VISIBLE); + Glide.with(imageView.getContext()) + .load(url) + .into(imageView); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b0d0301..71664e8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,9 +6,22 @@ android:layout_height="match_parent" tools:context=".activity.main.MainActivity"> - + android:layout_height="match_parent" + android:orientation="horizontal"> + +