——简化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%的位置才相应水平滑动手势)。
- 布局文件
复制代码 ...
- 自定义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.总结
以上就是这次这个小项目开发过程中的一些点,并没有高大上的东西,自己做个记录,如果能帮助到你那就更好了