@almoon 好的已更正
Posts made by Istream
-
Android新人任务(初步效果)
新人任务
- 完成首页、点单、订单、我的四个界面设计
- 底部导航栏在各个界面的跳转
- 首页为Fragment。banner效果和ImageView的跳转事件
- 点单界面为一个新的Activity。Tablayout + ViewPager实现页面滑动切换效果
- ViewPage中RecyclerView+CardView列表实现
2021/6/20 Check
代码规范是个严重的问题,这次check主要暴露出来的问题如下:-
对变量设置的范围限定没有严谨的概念,随意使用全局变量,虽然对这一个小工程影响很小,但是却是极其不专业、不对自己的代码负责的体现。
-
代码的规范上也是一些细节问题,注意空格的添加、命名的规范等
- xml文件中的id命名不能采用习惯性的驼峰规则,一律采用下划线连接形式,突出功能_名称
- 初始化一些数据杂项的方法采用initxxx()形式
- 不要乱用binding,最好只让每个Fragment和Activity持有自己的binding
-
代码设计模式上要一直向着简洁、高性能、高可读性靠拢
这一条让我受益匪浅。实现一个功能可以有很多途径,但是每一种途径都有其优劣之分。
-
要在另一个Fragment或Activity内拿到其他的Fragment或Activity实例,我的错误做法是无脑new一个新的实例出来,看似能够实现基础功能但却陷入了一个大坑:
从我们平时app的使用经验上谈,在我们对界面进行切换后很多时候前一个界面都不是立刻就销毁了的,要满足回退功能,在数据缓存这一条上来讲,就必不可能每一次切换都重新生成一个新的界面实例。所以必须清楚,new出来的这一个对象已经跟前面的完全区别开来了,而对一个project的整体上来讲,我这样的做法还没有养成一个整体意识。
-
而要实现不同的Fragment和Activity间的通信,更为优雅的做法是通过接口来完成。不要总将实例传进来再在当前的class块下对不是这个class所持有的东西进行操作,我们尽量避免“强盗行为”。每一个Fragment和Activity都是独立的个体,让他们之间的活动互不干扰,这样的设计模式就显得更为优雅和自如,设计逻辑上也更严密。
例如:实现HomeFragment中一个ImageView的点击跳转到ViewPageActivity
-
/*在HomeFragment中定义一个接口*/ private OnActivityChangeListener onActivityChangeListener; public interface OnActivityChangeListener { void onChange(); } /*在MainActivity中初始化homeFragment时实现接口方法*/ HomeFragment homeFragment = new HomeFragment(() -> { startActivity(intent); });
还有一些对于安卓底层源码的理解对写项目很有帮助,在理解的基础上去建立需求模型。
-
Android基础整理
项目管理与文件关联
在
.java
文件中应用.xml
文件setContentView(R.layout.activity_main); //引用activity_main.xml文件
Activity组件必须在
AndroidManifest.xml
注册<activity android:name=".MainActivity"/>
activity
跳转startActivity(new Intent(this,MainActivity2.class));
Context与Activity的关系
Context是一个抽象类,可以理解为对开发场景的抽象,Activity继承Context。
Activity通过Context接口去访问Android系统的服务和资源:
- 获取应用相关信息
- 获取系统/应用资源(Manager、color、drawable等)
- 四大组件之间的交互
- 文件相关
- 数据库相关
Context最终类型:Activity、Service、Application
- 与UI相关的场景都使用Activity类型Context(最常用)
- 较长生命周期使用Application类型Context
Activity.getApplication(); //语义性较强,用来获取Application实例,作用域:Activity、Service,但不能在BroadcastReceiver里使用 Activity.getApplicationContext(); //作用域更广,优先考虑这个全局的进程Context /*对这两个方法的区别主要在于作用域的区别*/
getBaseContext(); //返回构造函数指定的Context/setBaseContext()里传入的Context View.getContext(); //返回当前View对象的Context对象,通常是当前正在展示的Activity对象 Activity.this; //返回当前Activity的Context
Context引起内存泄漏
错误使用Context就可能引起内存泄漏问题
不要让生命周期长于Activity的对象持有到Activity的引用。
假如Activity A去getInstance获得instance对象,传入this,常驻内存的保存了传入的Activity A对象,并一直持有,即使Activity被销毁掉,但因为它的引用还存在,就不可能消失,这样就导致了内存泄漏。
LayoutInflater加载布局
- 获取LayoutInflater实例
- 调用该实例的inflate()方法来加载一个布局
- 调用主布局的addView()方法将它添加到LinearLayout中
inflate(int resource, ViewGroup root, boolean attachToRoot)
第三个参数设置为false表示将布局文件最外层的所有layout属性进行设置
如果root不为NULL第三参数设置为true会给加载的布局文件指定一个父布局
控件
1.textview
<LinearLayout> <TextView 属性设置 android:id="@+id/id名" android:text="" android:textColor="#FF000000" android:gravity="" </LinearLayout>
基础属性:
属性名 属性含义 属性值 layout_width 组件宽度 match_parent wrap_content,值+单位dp layout_height 组件高度 同上 id 设置id @+id/idName text 文本内容 @string/name(在strings.xml里设置) textColor 字体颜色 @color/name(在colors.xml里设置) textStyle 字体风格 normal(0),bold(1),italic(2) textSize 字体大小 单位用‘sp’(为满足适配条件) background 背景色 颜色或图片 gravity 内容的对齐方向 top,bottom,certer,center_vertical.... 通过设置的id获取控件:
v = findViewById() //in .java
跑马灯效果TextView
<TextView android:id="@+id/marqe" android:layout_width="match_parent" android:layout_height="200dp" android:text="@string/marqe" android:gravity="center_vertical" android:singleLine="true"<!--内容单行显示--> android:ellipsize="marquee" android:marqueeRepeatLimit:"marquee_forever" <!--字母动画重复次数--> android:focusable="true" android:focusableInTouchMode="true" <!--android:clickable="true"--> <requestFocus/> </TextView>
2.Button
<Button android:text="" android:layout_width="" android:layout_height="" android:background="@drawable/filename" <!--进行不同状态下按钮图案设置--> android:backgroundTint="@color/" </Button>
采用Drawable资源
new 一个drawable文件
root element: <selector>
通过<item_android:drawable="" android:state_pressed="">button事件处理
- 点击事件
- 长按事件
- 触摸事件
Botton btn =findViewById(R.id.btn); //点击事件 btn.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ //Log调试 } }); //长按事件 btn.setOnLongClickListener(new View.OnLongClickListener(){ @Override public void onLongClick(View v){ //Log调试 return false; } }); //触摸事件 btn.setOnTouchListener(new View.OnTouchListener(){ @Override public void onTouch(View v, MotionEvent event){ //Log调试 return false; } });
3.EditText
<EditText android:layout_width="" android:layout_height="" android:hint="请输入..." android:textColorHint= android:inputType="" <!--会弹出相应的输入键,和密码格式等--> android:drawableLeft="" </EditText>
4.ImageView
<ImageView android:src="@drawable/name" android:scaleType="fitXY" /*fitCenter,fitEnd,fitStart,center,centerInside,matrix..*/ android:maxWidth="" android:maxHeight=""最大宽高设置 android:adjustViewBounds="true"配合最大宽高自动调整 > </ImageView>
5.ProgressBar
<ProgressBar android:layout_width="" android:layout_height="" > </ProgressBar>
ProgressBar pb=findViewById(R.id.pb); pb.getVisibility(View.VISIBLE);//进度设置显示 pb.getVisibility(View.GONE);//进度设置不显示
6.Notification
- 创建一个NotificationManager
布局
<LinearLayout android:orientation="vertical" 纵向排列 android:gravity="center" android:divider="@drawable/divider" 加divider图片 > </LinearLayout>
<RelativeLayout 相对于父容器定位 android:layout_centerInParent="true" 中间位置 android:layout_alignParentLeft="true" 左对齐 > </RelativeLayout> <RelativeLayout 根据兄弟组件定位 android:layout_toLeftOf="@id/name" > </RelativeLayout>
margin 设置组件与父容器的间距 padding 设置组件内部的边距
<FrameLayout android:foreground="" > </FrameLayout>
<TableLayout android:collapseColumns="需要被隐藏的列的序号(0~)" android:stretchColumns="需要被拉伸的列的序号(0~)"条件是有剩余空间 android:shrinkColumns="需要收缩的列的序号(0~)"条件是有超出空间 > <TableRow> 控件排列显示在同一行,超出部分不显示 <Botton 子控件属性 android:layout_column="显示在第几列" android:layout_span="横向跨几列" > </Botton> </TableRow> </TableLayout> 常见的组合使用
constraintlayout
RecyclerView
实现一个RecyclerView需要的
- item.xml
- RecyclerViewAdapter
布局方式
GridLayoutManager() 传入context和列数
LinearLayoutManager
StaggeredGridLayoutManager
碎片Fragment
- 具备生命周期(子activity属性)
- 必须委托在activity中才能运行
碎片生命周期
onAttach()
碎片与活动创建关联onCreate()
onCreateView()
为碎片创建视图(加载布局)onActivityCreated()
与碎片相关联的活动创建完毕时调用onStart()
onResume
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
碎片的切换
1.创建碎片实例和待承接替换的碎片的容器(常用FrameLayout) 2.通过getSupportFragmentManager()获取FragmentManager 3.开启事务FragmentTransaction,调用beginTransaction()方法实现 4.通过replace()传入容器id,待添加的碎片实例来添加或替换碎片 5.提交事务commit()
碎片中获取context对象
调用**getActivity()**方法
碎片与活动 碎片与碎片
-
获取Fragment实例
Fragment fragment = (Fragment)getSupportFragmentManager().findFragmentById(R.id.fragment);
Glide上载图片
Glide.with(activity:this)//传入一个activity/context/fragment .load(string:"https:")//资源地址或id .apply(requestOptions) //占位符的使用 .into(name)//传入的容器对象
//自带默认占位图 RequestOptions requestOptions = new RequestOptions() .placeholder(R.drawable.hold) .error(R.drawable.error) .fallback(R.drawable.empty) .override(width:100,height:100)
泛型:把类型当成参数
接口
接口和实现是分离的
接口内拥有 的是常量和原型
接口是一个统一的规范,提供的是共有属性和方法原型
目前Android支持的最高jdk版本(jdk8)中,接口允许有默认方法