首页 文章 精选 留言 我的

精选列表

搜索[鸿蒙课程],共8118篇文章
优秀的个人博客,低调大师

Android官方开发文档Training系列课程中文版:Activity测试之创建运行测试

原文地址:http://android.xsoftlab.net/training/activity-testing/activity-basic-testing.html 为了验证在布局与功能上没有差池,很重要的一点就是需要为每个Activity创建对应的测试类。对每个测试类还需要创建单独的测试用例,这其中包含测试环境,测试条件以及对Activity测试的测试方法。实现这些便可以进行测试并获知结果。如果其中一项测试失败了,这便意味着在代码中可能存在潜在的问题。 创建测试用例 Activity测试都以结构化的方式实现。要确保将所有的测试放在一个单独的包中,与被测试代码区别开来。 依照惯例,测试包的包名应当由应用的包名+后缀”.tests”组成。在完成测试包的创建之后,添加一个Java类以用于测试。依照惯例,该类的名称应当由要测试的类的类名+后缀”Test”组成。 在Eclipse中创建测试用例的步骤如下: a.在工程中新建一个包。 b.设置包名为< your_app_package_name>.tests(例如,com.example.android.testingfun.tests),并点击Finish。 c.在该包名下创建一个类。 d.设置类名为< your_app_activity_name>Test(例如,MyFirstTestActivityTest),并点击Finish。 设置测试先决条件 测试先决条件由一系列用于测试的对象组成。设置这些先决条件需要重写setUp()方法以及tearDown()方法。TestRunner会在测试之前调用setUp()方法,在测试结束之后调用tearDown()方法。开发者可以通过这两个方法来确保测试被正常初始化以及可以确保在测试结束之后可以及时清理。 在Eclipse中设置测试先决条件: 1.将上面创建好的测试类继承于ActivityTestCase的任一子类。例如: public class MyFirstTestActivityTest extends ActivityInstrumentationTestCase2<MyFirstTestActivity> { 2.接下来,在这个类的内部添加构造方法以及setUp()方法,并添加要测试的Activity的变量声明。例如: public class MyFirstTestActivityTest extends ActivityInstrumentationTestCase2<MyFirstTestActivity> { private MyFirstTestActivity mFirstTestActivity; private TextView mFirstTestText; public MyFirstTestActivityTest() { super(MyFirstTestActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); mFirstTestActivity = getActivity(); mFirstTestText = (TextView) mFirstTestActivity .findViewById(R.id.my_first_test_text_view); } } 构造方法会在类初始化时由TestRunner调用,而setUp()方法则会在开始测试之前调用。 通常情况下,在setUp()方法内,应当实现以下内容: - 调用父类的setUp()方法。 - 通过以下步骤初始化先决条件: - 定义实例变量用于存储先决条件的状态。 - 创建并存储接下来要测试的Activity的引用。 - 持有Activity中需要进行测试的UI组件的引用。 可以通过getActivity()获取要测试的Activity的引用。 添加测试条件 在进行测试之前,还有一个步骤就是需要验证前一步是否设置正确,以及需要测试的对象是否已被正确的实例化、初始化。这样的话,便不需要确认测试本身是否有误,因为测试的先决条件已经发生了错误。依照惯例,用于验证先决条件的方法被称为testPreconditions(). 例如: public void testPreconditions() { assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity); assertNotNull(“mFirstTestText is null”, mFirstTestText); } 其中的判断方法来自于JUnit的Assert类。通常情况下可以使用这些判断方法来验证需要测试的指定条件是否为true。 - 如果条件为false,那么判断方法会抛出一个AssertionFailedError异常。该异常由TestRunner抛出。如果判断失败,那么可以通过判断方法的第一个参数得知是哪个条件失败。 - 如果条件为true,那么测试会顺利执行。 在这两种情况中,TestRunner会继续执行其它的判断方法。 添加测试方法 接下来,添加测试方法来验证Activity的布局与功能。 例如,如果Activity包含了一个TextView,你可以像下面这样添加一个测试方法来验证该TextView的文本是否正确: public void testMyFirstTestTextView_labelText() { final String expected = mFirstTestActivity.getString(R.string.my_first_test); final String actual = mFirstTestText.getText().toString(); assertEquals(expected, actual); } testMyFirstTestTextView_labelText()方法用于检测TextView的默认文本与定义在string.xml中的文本是否一致。 Note: 当命名测试方法时,可以使用下划线来分开要测试的内容,这种编写风格可以更容易明确测试的内容。 要执行比较,将期望的值与实际的值传给assertEquals()方法。如果两个值不相等,那么将会抛出一个AssertionFailedError异常。 如果添加testPreconditions()方法,那么请将测试代码放在testPreconditions()之后。 构建运行测试 在Eclipse中进行代码测试非常容易。 请执行以下步骤: 1.将Android设备连接到计算机。打开Setting菜单,选择Developer选项,并确保USB调试模式已开启。 2.在测试的类中选择RunAs > Android Junit Test. 3.在Android设备选择对话框中,选择刚刚连接好的设备,点击OK。 4.在JUnit界面中,验证测试是否通过。

优秀的个人博客,低调大师

Android官方开发文档Training系列课程中文版:布局性能优化之布局复用

原文地址:http://android.xsoftlab.net/training/improving-layouts/reusing-layouts.html 尽管Android提供了种类繁多的常用控件,但是有时你可能希望重用一些比较复杂的布局。如果要重用这些布局,可以使用< include/>标签与< merge/>标签,它们可将一个布局嵌入进另一个布局中。 可重用布局这项功能特别强大,它可以使你创建那些复杂的可重用布局。比方说,可以用来创建一个含有yes和no按钮的容器或者一个含有progressBar及一个文本框的容器。它还意味着程序可以对这些布局进行单独控制。所以,虽然说你可以通过自定义View的方式来实现更为复杂的UI组件,但是重用布局的方法更简便一些。 创建一个可重用的布局 如果你已经知道哪一个布局需要重用,那么就创建一个新的xml文件用来定义这个布局。下面就定义了一个ActionBar的布局文件,众所周知,ActionBar是会在每个Activity中统一出现的: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=”match_parent” android:layout_height="wrap_content" android:background="@color/titlebar_bg"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/gafricalogo" /> </FrameLayout> 使用< include/>标签 在希望添加重用布局的布局内,添加< include/>标签。下面的例子就是将上面的布局加入到了当前的布局中: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width=”match_parent” android:layout_height=”match_parent” android:background="@color/app_bg" android:gravity="center_horizontal"> <include layout="@layout/titlebar"/> <TextView android:layout_width=”match_parent” android:layout_height="wrap_content" android:text="@string/hello" android:padding="10dp" /> ... </LinearLayout> 你也可以重写布局的参数,但只仅限于以android:layout_*开头的布局参数。就像下面这样: <include android:id=”@+id/news_title” android:layout_width=”match_parent” android:layout_height=”match_parent” layout=”@layout/title”/> 如果你要重写< include>标签指定布局的布局属性,那么必须重写android:layout_height及android:layout_width这两个属性,以便使其它属性的作用生效。 使用< merge>标签 在将一个布局内嵌进另一个布局时,< merge>标签可以帮助消除冗余的View容器。举个例子,如果你的主布局是一个垂直的LinearLayout,在它的内部含有两个View,并且这两个View需要在多个布局中重用,那么重用这两个View的布局需要有一个root View。然而,使用单独的LinearLayout作为这个root View会导致在一个垂直的LinearLayout中又嵌了一个垂直的LinearLayout。其实这个内嵌的LinearLayout并不是我们真正想要的,此外它还会降低UI性能。 为了避免出现这种冗杂的View容器,你可以使用< merge>标签作为这两个View的root View: <merge xmlns:android="http://schemas.android.com/apk/res/android"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/add"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/delete"/> </merge> 那么现在再使用这个布局的时候,系统会自动忽略< merge>标签,并会将两个Button View直接加入到布局< include/>标签所指定的位置。

优秀的个人博客,低调大师

Android官方开发文档Training系列课程中文版:手势处理之拖拽或缩放

原文地址:https://developer.android.com/training/gestures/scale.html 这节课主要学习如何使用触摸手势来拖动、放大屏幕上的对象。 拖动对象 如果你的重点在Android 3.0以上的版本,那么你可以使用内置的拖拽事件监听器View.OnDragListener。 触摸手势最常见的操作就是使用它来拖动屏幕上的对象。下面的代码允许用户拖动屏幕上的图像。要注意以下几点: 在拖动操作中,APP会一直保持手指拖动的轨迹,就算是另一只手指触到屏幕也是。举个例子,想象一根手指在拖动着一张图像,这时用户将第二根手指放置到屏幕上,如果APP只是追踪单根手指的轨迹,那么它会将第二根手指作为默认位置,并会将图像移动到这个位置。 为了防止这样的事件发生,APP需要区分第一根手指与其它手指。为此,需要追踪 ACTION_POINTER_DOWN 及 ACTION_POINTER_UP 。ACTION_POINTER_DOWN 及 ACTION_POINTER_UP在第二根手指落下或抬起的时候由onTouchEvent()方法传回。 在ACTION_POINTER_UP的情况下,示例提取了这个事件的索引,并确保当前活动的指针不是那个已经不在屏幕上的指针。如果是那个指针的话,那么APP会选择一个不同的指针使其活动并保存它的X及Y的位置。一旦这个值被保存下来,那么APP将会使用正确指针的数据一直计算剩余移动的距离。 下面的代码允许用户在屏幕上拖动对象。它记录了当前活动指针的初始位置,计算了它所位移的距离,并将对象移动到新的位置上。 这里要注意,代码段使用了getActionMasked()方法。你应该一直使用这个方法来接收MotionEvent对象的活动。与getAction()方法不同,getActionMasked()工作于多点触控模式下。它会返回被执行的掩饰活动,不包括指针的索引比特。 // The ‘active pointer’ is the one currently moving our object. private int mActivePointerId = INVALID_POINTER_ID; @Override public boolean onTouchEvent(MotionEvent ev) { // Let the ScaleGestureDetector inspect all events. mScaleDetector.onTouchEvent(ev); final int action = MotionEventCompat.getActionMasked(ev); switch (action) { case MotionEvent.ACTION_DOWN: { final int pointerIndex = MotionEventCompat.getActionIndex(ev); final float x = MotionEventCompat.getX(ev, pointerIndex); final float y = MotionEventCompat.getY(ev, pointerIndex); // Remember where we started (for dragging) mLastTouchX = x; mLastTouchY = y; // Save the ID of this pointer (for dragging) mActivePointerId = MotionEventCompat.getPointerId(ev, 0); break; } case MotionEvent.ACTION_MOVE: { // Find the index of the active pointer and fetch its position final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, pointerIndex); final float y = MotionEventCompat.getY(ev, pointerIndex); // Calculate the distance moved final float dx = x - mLastTouchX; final float dy = y - mLastTouchY; mPosX += dx; mPosY += dy; invalidate(); // Remember this touch position for the next move event mLastTouchX = x; mLastTouchY = y; break; } case MotionEvent.ACTION_UP: { mActivePointerId = INVALID_POINTER_ID; break; } case MotionEvent.ACTION_CANCEL: { mActivePointerId = INVALID_POINTER_ID; break; } case MotionEvent.ACTION_POINTER_UP: { final int pointerIndex = MotionEventCompat.getActionIndex(ev); final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); if (pointerId == mActivePointerId) { // This was our active pointer going up. Choose a new // active pointer and adjust accordingly. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex); mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex); mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); } break; } } return true; } 平移 上面的部分展示了如何在屏幕上拖动对象。另一个通用的场景就是平移了,平移的意思是:用户的拖动动作引起的x及y轴方向上的滚动。上面的代码直接将MotionEvent拦截实现拖动。这部分的代码将会采用另一种更具有优势的方法,以便支持通用手势。它重写了GestureDetector.SimpleOnGestureListener的onScroll()方法。 只有用户在使用手指移动内容时,onScroll()才会被调用。onScroll()只有在手指按下的时候才会调用,一旦手指离开屏幕,那么平移手势也随之终止。 下面是onScroll()的使用摘要: // The current viewport. This rectangle represents the currently visible // chart domain and range. private RectF mCurrentViewport = new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX); // The current destination rectangle (in pixel coordinates) into which the // chart data should be drawn. private Rect mContentRect; private final GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { ... @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // Scrolling uses math based on the viewport (as opposed to math using pixels). // Pixel offset is the offset in screen pixels, while viewport offset is the // offset within the current viewport. float viewportOffsetX = distanceX * mCurrentViewport.width() / mContentRect.width(); float viewportOffsetY = -distanceY * mCurrentViewport.height() / mContentRect.height(); ... // Updates the viewport, refreshes the display. setViewportBottomLeft( mCurrentViewport.left + viewportOffsetX, mCurrentViewport.bottom + viewportOffsetY); ... return true; } 下面是setViewportBottomLeft()方法的实现,它主要实现了移动内容的逻辑: /** * Sets the current viewport (defined by mCurrentViewport) to the given * X and Y positions. Note that the Y value represents the topmost pixel position, * and thus the bottom of the mCurrentViewport rectangle. */ private void setViewportBottomLeft(float x, float y) { /* * Constrains within the scroll range. The scroll range is simply the viewport * extremes (AXIS_X_MAX, etc.) minus the viewport size. For example, if the * extremes were 0 and 10, and the viewport size was 2, the scroll range would * be 0 to 8. */ float curWidth = mCurrentViewport.width(); float curHeight = mCurrentViewport.height(); x = Math.max(AXIS_X_MIN, Math.min(x, AXIS_X_MAX - curWidth)); y = Math.max(AXIS_Y_MIN + curHeight, Math.min(y, AXIS_Y_MAX)); mCurrentViewport.set(x, y - curHeight, x + curWidth, y); // Invalidates the View to update the display. ViewCompat.postInvalidateOnAnimation(this); } 缩放 在Detecting Common Gestures中,我们讨论到GestureDetector可以帮助我们来检测比如滑动、滚动、长按等手势。而对于缩放,Android提供了ScaleGestureDetector. GestureDetector 以及 ScaleGestureDetector。 为了可以反馈检测到的手势事件,手势探测器使用了监听器对象ScaleGestureDetector.OnScaleGestureListener。如果你只关心部分手势的话,Android还提供了ScaleGestureDetector.SimpleOnScaleGestureListener,你可以通过重写它的方法来使用。 缩放基础示例 下面的代码是缩放所需要的基础: private ScaleGestureDetector mScaleDetector; private float mScaleFactor = 1.f; public MyCustomView(Context mContext){ ... // View code goes here ... mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); } @Override public boolean onTouchEvent(MotionEvent ev) { // Let the ScaleGestureDetector inspect all events. mScaleDetector.onTouchEvent(ev); return true; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.scale(mScaleFactor, mScaleFactor); ... // onDraw() code goes here ... canvas.restore(); } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); invalidate(); return true; } } 稍微复杂点的示例 下面是一个稍微复杂一点的示例,它摘自与这节课所提供的示例InteractiveChart(PS:示例工程请参见原网页)。InteractiveChart同时支持平移、缩放,它使用了ScaleGestureDetector的“平移”(getCurrentSpanX/Y)及“焦点” (getFocusX/Y)特性: @Override private RectF mCurrentViewport = new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX); private Rect mContentRect; private ScaleGestureDetector mScaleGestureDetector; ... public boolean onTouchEvent(MotionEvent event) { boolean retVal = mScaleGestureDetector.onTouchEvent(event); retVal = mGestureDetector.onTouchEvent(event) || retVal; return retVal || super.onTouchEvent(event); } /** * The scale listener, used for handling multi-finger scale gestures. */ private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { /** * This is the active focal point in terms of the viewport. Could be a local * variable but kept here to minimize per-frame allocations. */ private PointF viewportFocus = new PointF(); private float lastSpanX; private float lastSpanY; // Detects that new pointers are going down. @Override public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { lastSpanX = ScaleGestureDetectorCompat. getCurrentSpanX(scaleGestureDetector); lastSpanY = ScaleGestureDetectorCompat. getCurrentSpanY(scaleGestureDetector); return true; } @Override public boolean onScale(ScaleGestureDetector scaleGestureDetector) { float spanX = ScaleGestureDetectorCompat. getCurrentSpanX(scaleGestureDetector); float spanY = ScaleGestureDetectorCompat. getCurrentSpanY(scaleGestureDetector); float newWidth = lastSpanX / spanX * mCurrentViewport.width(); float newHeight = lastSpanY / spanY * mCurrentViewport.height(); float focusX = scaleGestureDetector.getFocusX(); float focusY = scaleGestureDetector.getFocusY(); // Makes sure that the chart point is within the chart region. // See the sample for the implementation of hitTest(). hitTest(scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), viewportFocus); mCurrentViewport.set( viewportFocus.x - newWidth * (focusX - mContentRect.left) / mContentRect.width(), viewportFocus.y - newHeight * (mContentRect.bottom - focusY) / mContentRect.height(), 0, 0); mCurrentViewport.right = mCurrentViewport.left + newWidth; mCurrentViewport.bottom = mCurrentViewport.top + newHeight; ... // Invalidates the View to update the display. ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this); lastSpanX = spanX; lastSpanY = spanY; return true; } };

优秀的个人博客,低调大师

酷瓜云课堂(内网版)v1.0.4 发布,局域网在线课程解决方案

更新内容 增加授权过期提醒 增加站点是否公开访问配置 优化API基类 优化站点信息API输出脱敏 优化单章节层级显示 优化热门作者,答主和问题 优化表单数据提交体验 修正学习记录active_time拼写错误 修正后台设置测试推流鉴权问题 修正考试人数重复计数问题 修正用户中心在线统计问题 使用绝对http全路径输出文章和问题封面 系统介绍 酷瓜云课堂内网版,采用C扩展框架Phalcon开发,使用本地基础服务,无营销相关功能,主要适用于公司,学校等内部网络环境使用。 系统优势 基于高性能 C 扩展 Phalcon 框架,响应快速,安全可靠。音视频转码相关服务基于优秀的开源项目 ffmpeg,成熟高效。业务代码全部开放,方便二次开发。 系统功能 实现了点播、直播、专栏、问答、积分等常见功能,具体请访问系统演示 友情提示 演示站点带宽只有1M,文件全在本地存储,响应比较慢,请在本地部署系统 系统演示: 前台演示 后台演示 演示账号:100015@163.com / 123456 (前后台通用) 项目组件 后台框架:phalcon 3.4.5 前端框架:layui 2.7.6 全文检索:xunsearch 1.4.9 即时通讯:workerman 3.5.22 基础依赖:php7.3, mysql5.7, redis5.0 项目文档 运行环境搭建 系统服务配置 客户终端配置

优秀的个人博客,低调大师

德哥PG系列课程直播(第15讲):PostgreSQL 新类型提高开发生产力

直播回顾 地址:https://yq.aliyun.com/live/909 知识点 知识点:JSON, ARRAY, RANGE 学习资料 1、PostgreSQL 店铺运营实践 - JSON[]数组 内部标签数据等值、范围检索100倍+加速示例 (含,单值+多值列合成) https://yq.aliyun.com/articles/501431标签:PostgreSQL , json , 数组 , 多值 , 等值 , 多值 , 一棵树 , 多颗树 , gin , btree , gist 2、PostgreSQL UDF实现tsvector(全文检索), array(数组)多值字段与scalar(单值字段)类型的整合索引(类分区索引) - 单值与多值类型复合查询性能提速100倍+ 案例 (含,单值+多值列合成)标签:PostgreSQL , 单值列 , 多值列 , GIN倒排索引 , 多值列变异 , 分区索引 , 分区表 , 变异索引 3、PostgreSQL 多重含义数组检索与条件过滤 (标签1:属性, 标签n:属性) - 包括UPSERT操作如何修改数组、追加数组元素标签:PostgreSQL , 多重函数数组 , UDF索引 , 过滤 , 文本处理 4、会议室预定系统实践(轻松解放开发) - PostgreSQL tsrange(时间范围类型) + 排他约束标签:PostgreSQL , tsrange , 范围 , exclude using , 排他约束 , btree_gist , 会议室预定 , 时间重叠 , 空间重叠 5、聊聊between and的坑 和 神奇的解法标签:PostgreSQL , 物联网 , 智能DNS , range , iprange , intrange , 排他约束 , GiST索引 往期回顾 PostgreSQL多场景阿里云沙箱实验(第14讲):PostgreSQL 数据清洗、采样、脱敏、批处理、合并 https://yq.aliyun.com/live/885PostgreSQL多场景阿里云沙箱实验(第13讲):PostgreSQL 图式关系数据应用实践 https://yq.aliyun.com/live/869PostgreSQL多场景阿里云沙箱实验(第12讲):PostgreSQL 物联网最佳实践https://yq.aliyun.com/live/846PostgreSQL多场景阿里云沙箱实验(第11讲):PostgreSQL 在社交应用领域的最佳实践 https://yq.aliyun.com/live/824PostgreSQL多场景阿里云沙箱实验(第10讲):PostgreSQL 时空调度数据库实践 https://yq.aliyun.com/live/807PostgreSQL多场景阿里云沙箱实验(第9讲):PostgreSQL 时空业务实践 https://yq.aliyun.com/live/794PostgreSQL多场景阿里云沙箱实验(第8讲):PostgreSQL 简单空间应用实践 https://yq.aliyun.com/live/783PostgreSQL多场景阿里云沙箱实验(第7讲):PostgreSQL 并行计算 https://yq.aliyun.com/live/733PostgreSQL多场景阿里云沙箱实验(第6讲):PostgreSQL 用户画像系统实践 https://yq.aliyun.com/live/710PostgreSQL多场景阿里云沙箱实验(第5讲):PostgreSQL 估值、概率计算 https://yq.aliyun.com/live/691PostgreSQL多场景阿里云沙箱实验(第4讲):PostgreSQL 实时多维分析 https://yq.aliyun.com/live/659PostgreSQL多场景阿里云沙箱实验(第3讲):PostgreSQL 实时搜索实践https://yq.aliyun.com/live/647PostgreSQL多场景阿里云沙箱实验(第2讲):PG秒杀场景实践https://yq.aliyun.com/live/615PostgreSQL多场景阿里云沙箱实验(第1讲):如何快速构建海量逼真测试数据https://yq.aliyun.com/live/594 主讲人 德哥(云栖社区昵称:德哥)阿里云数据库专家,PostgreSQL中国社区校长。 格言:公益是一辈子的事, I'm digoal, just do it. 专家已经在社区发布了1946篇技术博文,很快将突破2000篇。厉害了!想要成为德哥粉丝请直接点击这里。 直播时间 时间:2019年3月6日 19:30 直播地址 PostgreSQL技术进阶群,钉钉扫码入群看直播

优秀的个人博客,低调大师

5.kotlin安卓实践课程-用kotlin写第一个activity(具体实现)

简介 主要会通过安卓实战来讲解kotlin语法和实际应用,本教程设及知识点包括框架模式mvp+mvvm, Databinding(数据绑定框架),Dagger2(依赖注入框架),DeepLink(页面路由框架),Rxjava,RxAndroid(异步操作框架),Retrofit,Okhtttp等,不过本教程重点在kotlin所以这些框架需要了解可自行百度。 针对人群:Android中级以上,kotlin入门 接上一篇 MainActivity完整代码,这个类主要完成了viewpager+fragment这种经典结构的绑定和底部导航栏点击事件处理 class MainActivity : BaseBindingActivity<ActivityMainBinding>(),RandomContract.View { //语法点1: MutableList lateinit var mFragments: MutableList<Fragment> @Inject lateinit var mPresenter : RandomPresenter override fun createDataBinding(savedInstanceState: Bundle?): ActivityMainBinding { return DataBindingUtil.setContentView(this, R.layout.activity_main) } override fun initView() { initFragments() getMainComponent().plus(RandomModule(this)).inject(this) viewPager.adapter = object : FragmentPagerAdapter(supportFragmentManager) { override fun getItem(position: Int) = mFragments[position] override fun getCount() = mFragments.size } viewPager.offscreenPageLimit = 4 navigationView.setOnNavigationItemSelectedListener { item -> var tab = 0 when (item.itemId) { R.id.menu_android -> tab = 0 R.id.menu_ios -> tab = 1 R.id.menu_girl -> tab = 2 R.id.menu_about -> tab = 3 } viewPager.currentItem = tab false } floatingButton.setOnClickListener { mPresenter.getRandom("Android") } } override fun onRandom(goods :FuckGoods) { val url = URLEncoder.encode(goods.url) toast("手气不错~") GankRouter.router(this,GankClientUri.DETAIL + url) } private fun initFragments() { mFragments = ArrayList() mFragments.add(AndroidFragment.newInstance()) mFragments.add(IOSFragment.newInstance()) mFragments.add(GirlFragment.newInstance()) mFragments.add(FragmentHolder()) } } 语法点1:MutableList lateinit var mFragments: MutableList<Fragment> MutableList<E>接口继承于List<E>,MutableCollection<E>,是对只读集合的扩展,增加了了对集合的添加及删除元素的操作。kotlin也有List但是它不同于java的List,kotlin的List只有只读属性,就是可以查询但不能增删改 语法点2:匿名对象 viewPager.adapter = object : FragmentPagerAdapter(supportFragmentManager) { override fun getItem(position: Int) = mFragments[position] override fun getCount() = mFragments.size } 这里的object就是匿名对象和java的一样,注意一下kotlin的实现形式 语法点3:属性的使用 大家可能注意到了,viewPager.adapter我们java里面都是要调用setAdapter的,这里其实用编辑器点击adapter你会发现,其实kotlin会自动调用这个方法 ,所以kotlin要使用一个属性,只需要使用名称引用即可 viewPager.offscreenPageLimit = 4 这样的属性使用的例子随处可见 语法点4:when函数 when (item.itemId) { R.id.menu_android -> tab = 0 R.id.menu_ios -> tab = 1 R.id.menu_girl -> tab = 2 R.id.menu_about -> tab = 3 } when是表达式,所以它能够返回存储到变量里的值,它更强大的应用可以看看下面的代码 val res = when { x in 1..10 -> "cheap" s.contains("hello") -> "it's a welcome!" v is ViewGroup -> "child count: ${v.getChildCount()}" else -> "" } when条件左边可以做任何很多事,因为它是表达式,比传统的switch强太多 欢迎一起交流,有问题加群交流 kotlin实战交流群群二维码.png

优秀的个人博客,低调大师

Linux运维课程一览(不定期更新学习要点及重难点笔记)

第一阶段计算机网络基础 ISO/OSI参考模型和TCP/IP协议 网络层协议和IP地址划分 CISCO/IOS操作系统 路由原理 EIGRP和OSPF路由协议 访问控制列表 网络地址转换技术 交换机原理 生成树协议 VLAN技术 第二阶段Linux基础 Linux系统管理 简介、安装 常用命令 VI编辑器 软件管理 用户和用户组管理 权限管理 文件系统管理 LVM和RAID管理 SHELL基础、SHELL编程 启动管理 服务管理 系统管理 日志系统 备份与恢复 第三阶段Linux基础服务 Linux网络基础 DHCP服务器配置 VSFTPD服务器部署 SAMBA服务器部署 NFS服务器部署 DNS服务器 APACHE服务器配置 LNMP环境部署 NGINX服务器 邮件服务器部署 RSYNC数据同步 NTP时间服务器 第四阶段MySQL SQL语句 用户权限管理 数据导入与导出 数据库备份与恢复 MySQL主从备份 MySQL读写分离 第五阶段Linux集群管理 KickStart无人值守安装 Squid正向代理 Squid反向代理 LVS负载均衡集群 Keeppalived高可用性架构 Nagios/cacti监控服务器 网络存储技术iscsi 第六阶段云计算 云计算概述与发展 虚拟化技术 Xen虚拟化技术 KVM虚拟化实现 KVM虚拟机管理技术 第七阶段SElinux/iptables SELinux安全策略 防火墙概述 TCP-wrappers防护机制 Iptables防火墙语法 常用防火墙脚本 将iptables作为NAT路由器 本文转自 chaijowin 51CTO博客,原文链接:http://blog.51cto.com/jowin/1629860,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册