Android Wear(Wear OS)开发 ——简化Wear版Wx开发过程中的一些总结

1. 微光模式

智能手表的电池容量都比较低,导致续航也比较短。为了延长手表的续航,Wear OS 手表在没有操作一段时间后,会进入微光模式 AmbientMode。微光模式就是一个省电模式,这个模式会在低功耗下运行,默认情况下,手表会离开当前的应用,返回到表盘的界面。但有时候,我们希望开发的应用在某些情况下,可以一直保持可见的状态,这就需要我们使用支持微光模式的 Activity 了。

  • 一般wear应用的activity继承自WearableActivity,然后activity里调用setAmbientEnabled()来支持微光模式,但是我们的工程的页面架构是一个activity+多fragment的形式;这要求我们的activity必须继承自FragmentActivity,因而需要使用另一种方式来支持微光模式: HomeActivity继承FragmentActivity,同时实现AmbientModeSupport.AmbientCallbackProvider接口,在onCreate里调用AmbientModeSupport.attach(this),它返回一个AmbientModeSupport.AmbientController对象,可用于查询当前微光模式所处的状态。
 public class HomeActivity extends FragmentActivity implements AmbientModeSupport.AmbientCallbackProvider
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        Log.d(TAG, "onCreate");
        AmbientModeSupport.attach(this);
    }

AmbientModeSupport.AmbientCallbackProvider定义如下,我们可以实现这些接口,来对微光模式的不同状态进行处理。

public abstract static class AmbientCallback {
    public AmbientCallback() {
    }

    public void onEnterAmbient(Bundle ambientDetails) {
    }

    public void onUpdateAmbient() {
    }

    public void onExitAmbient() {
    }

    public void onAmbientOffloadInvalidated() {
    }
}

2. Wear OS右划退出

  • wear针对穿戴设备的操作特点,有个默认的手势:右划退出当前全屏Activity,这对于一般页面操作很方便,ios和Android应用很多都有类似的支持,但对于手表这种屏幕比较小设备,wear提供的是全屏响应手势的,并不像手机是左侧边缘才响应,这样wear的交互设计上一般不建议再使用水平滑动的手势,但凡事总有例外,我们的应用中就有一个右划的手势操作,解决方案就是使用SwipeDismissFrameLayout来包裹我们的视图,我们的视图需要重写canScrollHorizontally方法,返回true,这时就启动了边缘滑动状态(屏幕左侧10%的位置才相应水平滑动手势)。
  • 布局文件
<android.support.wear.widget.SwipeDismissFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.tencent.ui.voip.SwipeViewContainer
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--我们自己的视图-->
        ...
    </com.tencent.ui.voip.SwipeViewContainer>
</android.support.wear.widget.SwipeDismissFrameLayout>
  • 自定义View SwipeViewContainer,canScrollHorizontally返回true。
public class SwipeViewContainer extends RelativeLayout {
    ....

    @Override
    public boolean canScrollHorizontally (int direction) {
        return true;
    }
}
  • 右划退出在实际使用过程中发现一个问题,被划出的页面(Fragment)退出后又会再闪现了一下,造成很不好的体验,在网上没有找到有用的信息,只能自己摸索。
    • 首先想到的是不是fragment的切换动画引起的, FragmentTransaction定义了如下几种切换方式,但即使设置成TRANSIT_NONE,还是依然会有问题,看来不是切换动画的问题。
    public static final int TRANSIT_ENTER_MASK = 4096;
    public static final int TRANSIT_EXIT_MASK = 8192;
    public static final int TRANSIT_UNSET = -1;
    public static final int TRANSIT_NONE = 0;
    public static final int TRANSIT_FRAGMENT_OPEN = 4097;
    public static final int TRANSIT_FRAGMENT_CLOSE = 8194;
    public static final int TRANSIT_FRAGMENT_FADE = 4099;
    
    • 然后想能不能在fragment切换过程中对旧页面进行一些操作,这就需要对滑动操作的过程进行监听,SwipeDismissFrameLayout类提供了实现的方法,让我们的视图包裹在SwipeDismissFrameLayout里,然后设置回调SwipeDismissFrameLayout.Callback,在事件的回调方法里进行相关处理。
    private final SwipeDismissFrameLayout.Callback mCallback =
        new SwipeDismissFrameLayout.Callback() {
            public void onDismissed(SwipeDismissFrameLayout layout) {
                Log.d(TAG, "onDismissed()");
                //To do
            }
            public void onSwipeStarted(SwipeDismissFrameLayout layout) {
                Log.d(TAG, "onSwipeStarted()");
            }
            public void onSwipeCanceled(SwipeDismissFrameLayout layout) {
                Log.d(TAG, "onSwipeCanceled()");
            }
        };
    public View onCreateView(@NonNull LayoutInflater inflater, @LayoutRes int layoutid) {
        SwipeDismissFrameLayout swipeLayout = new SwipeDismissFrameLayout(getActivity());
        inflatedView = inflater.inflate(layoutid, swipeLayout, false);
    
        swipeLayout.addView(inflatedView);
        swipeLayout.addCallback(mCallback);
        return swipeLayout;
    }
    
    一开始想在onDismissed回调里将当期fragment隐藏(如下),但仍没有任何用处,即使在onSwipeStarted调用没任何作用,最后直接来最暴力的,将当期fragment的View直接设置成GONE,这样闪现的问题就解决了。
    //不行
    getActivity().getSupportFragmentManager().beginTransaction().hide(curFragment);
    //搞定
    inflatedView.setVisibility(View.GONE);
    

3.Fragment

  • 应用中多个frament彼此进行切换,要求右划后可以回到上一个fragment,要使用add而不是replace,这里需要操作fragment的回退栈。

进入

FragmentTransaction transaction =  getActivity().getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_right_out);
transaction.add(R.id.fragment_container, messageListFragment);
transaction.addToBackStack(null);
transaction.commit();

回退

getActivity().getSupportFragmentManager().popBackStack();

同一个fragment不能重复add,不然会出错,这里需要处理一下

if (messageFragment.isAdded()){
    transaction.remove(messageFragment);
}
  • 使用回退的方式进入原来的fragment,是不会调用Fragment的任何生命周期回调的,那我们有时候原页面又需要知道这个操作,比如需要更新一下页面的数据或状态等,那我们就需要手动去监听,那监听源是什么呢,我们想到这里发生改变的全局数据就是我们的回退栈,而FragmentManager刚好也提供监听回退栈变化的listener,我们重写listener里的onBackStackChanged接口,在里面我们找到要进入的fragment,然后主动触发它的生命周期方法,比如onResume。
  FragmentManager mgrFragment = getSupportFragmentManager();
  mgrFragment.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
      @Override
      public void onBackStackChanged() {
          FragmentManager manager = getSupportFragmentManager();
          if (fragmentStackSize > manager.getBackStackEntryCount()) {//判断是回退操作
              if (manager != null) {
                  Fragment currFrag = manager.findFragmentById(R.id.fragment_container);
                  currFrag.onResume();
              }
          }
          fragmentStackSize = manager.getBackStackEntryCount();
      }
  });

4.性能问题

应用里有用RecycleView来显示列表,列表里有图片,我们使用Glide来显示的,这里需要注意的一点是,在使用Glide的时候,应该在别处对其进行一下初始化,不要在onBindViewHolder里就直接使用,这会导致第一次打开页面很慢。同样道理,onBindViewHolder里用到东西,最好都事先加载好。图片可以根据实际需求进行剪裁,避免使用原图。

RequestOptions options = new RequestOptions();
        options.centerCrop();
        options.override(width, height);
        Glide.with(mContext).load(conversation.getHeadimagepath()).into(holder.avatar);

5.总结

以上就是这次这个小项目开发过程中的一些点,并没有高大上的东西,自己做个记录,如果能帮助到你那就更好了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容