• 安卓项目总结——基于喜马拉雅SDK的安卓项目练习


    写在前面

    本APP代码已放在了github地址,需要的可以到这里去下载。

    正文

    1. 需要导入网络的相关依赖:

      // SDK在解析请求返回的JSON数据时用到
      api 'com.google.code.gson:gson:2.8.1'
      // SDK联网框架使用okhttp
      api 'com.squareup.okhttp3:okhttp:3.11.0'
      // SDK联网框架使用okhttp
      api 'com.squareup.okio:okio:1.15.0'
      // v4包
      api 'com.android.support:support-v4:28.0.0'
      
    2. 出现了604网络请求错误,首先检查是否导入了网络权限:

          <!--连接网络-->
          <uses-permission android:name="android.permission.INTERNET" />
          <!--用于管理监听网络状态的变化-->
          <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
          <!--用于管理监听网络状态的变化-->
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
          <!--用于管理监听网络状态的变化-->
          <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
          <!--获取电话的状态,在打电话的时候暂停播放-->
          <uses-permission android:name="android.permission.READ_PHONE_STATE" />
          <!--target >=28 需要设置此权限 -->
          <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
      

      然后再检查自己的API版本,如果是大于27的版本(在build.grade里,如下图)

      那么已经不再支持http请求了(即默认的请求访问),需要切换成https请求:

              CommonRequest mXimalaya = CommonRequest.getInstanse();
              mXimalaya.setUseHttps(true);
      

      或者直接设置支持明文访问:(在manifest.xml里)

      <application
          android:usesCleartextTraffic="true">
      

      还有另外一种设置方法,可以去百度查询一下。

    3. 在创建MainContentAdapter时候,使用了AndroidX后,旧版的FragmentPagerAdapter的构造方法被标注过时,建议我们使用新版的:

          public MainContentAdapter(@NonNull FragmentManager fm, int behavior) {
              super(fm, behavior);
          }
      

      这里需要多传一个参数behavior,我们点开源码查看注释,发现有两种behavior:

    一种是已经标注过时的,一种是新版的。我们传入新版的:

            MainContentAdapter mainContentAdapter = new MainContentAdapter(supportFragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    
    

    至于这二者的差别,根据百度的相关介绍,

    具体的我也看不太懂,先做记录。

    1. 在写代码的过程中,我们需要把逻辑层的代码和UI层的代码分开(解耦),这样做一是可以让我们的代码思路更加清晰,二是更加安全,并且可以更好的复用代码。

      要实现解耦,首先我我们要定义一个获取接口来把需要的方法都写入,再提供回调接口,并在获取接口中提供对回调接口的注册和释放方法。之后我们书写获取接口的实现类,写入获取数据的逻辑代码。我们在activty或者fragment用到的时候,直接创建一个逻辑层接口(获取接口)的对象,并调用其对象的方法,然后注册回调接口,并实现回调即可。当回调成功后,我们就直接更新UI就可以了。

      其实仔细想一想,在安卓开发中回调这个概念用到的很多。这样的解释未免还是太过抽象了,还是要在实际开发中养成这样的习惯,不断优化自己的代码规范,从而加深自己的理解。

    2. 在我们写UILoader时,我们把前两个构造方法都改成了this的方式,如下:

          public UILoader(@NonNull Context context) {
              this(context,null);
          }
      
          public UILoader(@NonNull Context context, @Nullable AttributeSet attrs) {
              this(context, attrs,0);
          }
      
          public UILoader(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
              super(context, attrs, defStyleAttr);
      
          }
      

      这样的效果是我们可以让入口唯一,即都调用第三个构造方法。

    3. 使用UILoader的思路整理:

      我们首先发起网络请求,在请求前设置为加载中的UI,在请求成功和失败后各自根据条件判断加载哪个view(都调用callback里的方法),在主fragment中实现这几个callback的方法,调用UILoader来更新UI,UILoader截获请求后根据传入的状态来判断显示哪个。

    4. 隐藏导航栏,设置状态栏颜色为透明的代码:

      getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
       getWindow().setStatusBarColor(Color.TRANSPARENT);
      
    5. Toast去掉前面的应用名称的方法:我们可以先生成一个Toast对象,通过对这个Toast对象实例设置text再显示就不会有应用名了,可以直接使用下面的工具类:

      /**
       * FileName: ToastUtil
       * Author: LiuGe
       * Date: 2020/7/29 18:15
       * Description: Toast工具类
       */
      public class ToastUtil {
      
          public static void showShort(Context context, CharSequence message) {
      
              Toast toast = Toast.makeText(context, null, Toast.LENGTH_SHORT);
      
              toast.setText(message);
      
              toast.show();
      
          }
      
          public static void showLong(Context context, CharSequence message) {
      
              Toast toast = Toast.makeText(context, null, Toast.LENGTH_LONG);
      
              toast.setText(message);
      
              toast.show();
      
          }
      }
      
    6. 在使用SharedPreference时,使用commit方法提交数据IDE提示考虑使用apply,于是百度了一下二者的差别:commit是同步提交,且有返回值表示是否提交成功,apply是异步提交,且无返回值。而SharedPreference是单实例,一般不会出现并发冲突,故如果对提交结果不关心建议使用apply,如果关心提交结果且需要同步提交的话可以使用commit。

    7. 在返回界面时,由于没有更新状态,需要在presenter层里写一个更新UI和进度条的方法:

          private void handlePlayState(IPlayerCallback iPlayerCallback) {
              int playerStatus = mPlayerManager.getPlayerStatus();
              // 根据状态调用接口的方法
              if (PlayerConstants.STATE_STARTED == playerStatus) {
                  iPlayerCallback.onPlayStart();
              }else{
                  iPlayerCallback.onPlayStop();
              }
          }
      
    8. 想要设置PopupWindow能够点击外部关闭的效果,可以使用如下代码:

              // 这里要注意:设置setOutsideTouchable要先设置:setBackgroundDrawable
              // 否则点击外部无法关闭pop
              setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
              setOutsideTouchable(true);
      

      这里需要注意,最好先设置一下setBackgroundDrawable,否则可能会出现无法关闭的Bug

    9. 实现PopupWindow的显示后有一定透明度的思路:获取Window对象,对其中的attributes里的alpha属性做一个设置(alpha属性:透明度),如下代码:

          /**
           * 设置弹出框的透明度
           * @param alpha
           */
          public void updateBgAlpha(float alpha){
              Window window = getWindow();
              WindowManager.LayoutParams attributes = window.getAttributes();
              attributes.alpha = alpha;
              window.setAttributes(attributes);
          }
      
    10. 判空的重要性:在我们开发APP的时候,对于不确定的结果一定要判空处理,如该项目中,若用户网速太慢,没有正确的获取到图片路径,那么就会导致程序崩溃。一定要对容易为空的内容进行一个判空处理。

    11. 隐藏键盘的代码如下:

              // 隐藏键盘
              InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
              imm.hideSoftInputFromWindow(mInputBox.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
      

      其中的HIDE_IMPLICIT_ONLY为一个常量,是该方法的默认使用值。

    12. 在做订阅和取消订阅功能时,出了一个Bug:点击订阅后UI会更改,但实际上只更新了UI,点击取消订阅时还是会弹出订阅成功,因为只更新了UI,没有更新presenter里保存的map,需要在presenter的添加删除方法里在更新UI前先查询数据库,更新里面的map:

          @Override
          public void onAddResult(final boolean isSuccess) {
              // 调用查询方法,更新mData,确保能正确更新UI
              listSubscriptions();
              // 添加结果的回调
              BaseApplication.getHandler().post(new Runnable() {
                  @Override
                  public void run() {
                      for (ISubscriptionCallback callback : mCallbacks) {
                          callback.onAddResult(isSuccess);
                      }
                  }
              });
          }
      

      (应该是我在跟着视频敲的时候漏写了。)

    总结

    总的来说,安卓的开发与web的开发相差还是很大的,在安卓开发中,需要考虑很多的情况,而在web中很多情况都会被浏览器处理掉,如没有数据,网络错误,数据为空等等这都需要开发者去处理,但在web上我一直没有做过这方面的处理,就算做过也只是简单的做了一个访问错误界面。或许正规点的项目都会这样搞吧。通过这次学习,大概了解了安卓开发的思路,但也让我意识到自己对于某些基础组件的了解还是太少了。这几天老师的任务也下来了,要让我们学大数据方面的内容,接下来学习什么再看吧。

  • 相关阅读:
    Redmine入门-安装
    【Spring Cloud笔记】 Eureka通过集群实现高可用
    【SpringBoot笔记】SpringBoot整合Druid数据连接池
    【Spring Cloud笔记】 断路器-hystrix
    【Spring Cloud笔记】Eureka注册中心增加权限认证
    Jenkins实现简单的CI功能
    【SpringBoot笔记】SpringBoot如何正确关闭应用
    Activi相关表归纳
    阿里云MySQL远程连接不上问题
    Storm入门-Storm与Spark对比
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/13428179.html
Copyright © 2020-2023  润新知