Fork me on GitHub
行锋

低头走路,抬头思考


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索

C#

发表于 2018-10-17 | 分类于 C#

双问号操作符意思是取所赋值??左边的,如果左边为null,取所赋值??右边的,双问号操作符意思是取所赋值??左边的,如果左边为null,取所赋值??右边的,

https://blog.csdn.net/zmh458/article/details/78935172
https://www.cnblogs.com/lanpingwang/p/6596758.html
https://www.cnblogs.com/Inspire-Yi/p/6230567.html

https://www.jianshu.com/p/c82ef6babf8e

https://www.cnblogs.com/caofangsheng/p/5715876.html
https://blog.csdn.net/beglorious/article/details/39637475

https://www.cnblogs.com/servicehot/p/6510199.html

首先我觉得action的跳转大致可以这样归一下类,跳转到同一控制器内的action和不同控制器内的action、带有参数的action跳转和不带参数的action跳转。

一、RedirectToAction(“Index”);//一个参数时在本Controller下,不传入参数。

二、RedirectToAction(ActionName,ControllerName) //可以直接跳到别的Controller.

三、RedirectToRoute(new {controller=“Home”,action=“Index”});//可跳到其他controller

四、RedirectToRoute(new {controller=“Home”,action=“Index”, id=param});//可跳到其他controller,带参数。

五、Response.Redirect(“Index?id=1”);//适用于本controller下的方法名称,可带参数。
六、return Redirect(“Index”);//适用于本controller下的方法名称。

七、return View(“Index”); //直接显示对应的页面 不经过执行Controller的方法。
八、return View("~/Views/Home/Index.aspx");//这种方法是写全路径,直接显示页面,不经过Controller方法
九、return View();//直接显示页面,不经过Controller方法

https://blog.csdn.net/zhensoft163/article/details/7174661?utm_source=blogxgwz1
一般情况下我们返回的都是本页面,所以使用return View()就可以解决问题了,

https://www.cnblogs.com/Cwj-XFH/p/5956142.html
Model验证是ASP.NET MVC中的重要部分,它主要用于判断输入的数据类型及值是否符合我们设定的规则,这篇文章就介绍下ASP.NET MVC中Model验证的几种方式。

后台验证
DataAnnotation
ValidationAttribute
IValidatableObject
IDataErrorInfo
前端验证

ViewData和ViewBag

https://blog.csdn.net/pasic/article/details/7093802

https://www.cnblogs.com/webapi/p/9505400.html

系列文章:
https://blog.csdn.net/ydm19891101/article/details/43338999

WebForm与MVC的本质区别:请求的url不同

https://blog.csdn.net/liupantao/article/details/78582078?locationNum=3&fps=1

MVC action 返回javascriptResult 需要引入的文件是
需要引用这个文件 : jquery.unobtrusive-ajax.min.js

同时 用javascrptResult 作为action的返回结果 的话 ,前台必须用ajax.BeginForm

https://www.cnblogs.com/zjf1987/p/ActionResult.html

React全家桶

发表于 2018-10-15 | 分类于 React

React全家桶+Antd共享单车后台管理系统

react基础知识

Vue生态:Vue+Vue-Router+Vuex+Axios+Babel+Webpack
React生态:React+React-Router+Redux+Axios+Babel+Webpack

编程式实现:需要以具体代码表达在哪里做什么,如何实现
声明式实现:只需声明在哪里做什么,无需关心如何实现

https://react.docschina.org/
https://reactjs.org.cn/
http://facebook.github.io/react/

yarn: https://yarnpkg.com/zh-Hans/

  • yarn init
  • yarn add
  • yarn remove
  • yarn install

react生命周期

react-router /react-router-dom

按需加载:
Antd中less样式
yarn eject:暴露webpack配置,

less-loader安装
webpack.config.xxx.js

修改完之后,重启项目

https://ant.design/docs/react/use-with-create-react-app-cn

babel-plugin-import

css3 calc属性
height:calc(100vh)

jsonp:https://www.npmjs.com/package/jsonp

浏览器添加debugger

伪类方式

项目中前端路由用的是 React-Router V4。

官方文档:https://reacttraining.com/react-router/web/guides/quick-start

中文文档:http://reacttraining.cn/

React-Router 4.0
React-Router:基础包
React-Router-DOM:浏览器端实现

https://segmentfault.com/a/1190000011399153

箭头函数不加{}表示直接返回结果
this.props.match.params.XXX
处理404则不设置path,只设置component即可
路由外面添加Switch

详情页面、登录页面、主页面是同层级页面,还有其他自页面嵌套路由

App.js设置为{this.props.children}代表可以接受任何组件,APP组件作为HashRouter的根组件

子路由、子组件模式

传参数需要箭头函数

Modal.confirm() 等价于 Modal[‘confirm’]

{}里面必须是一个根对象

https://blog.csdn.net/little_blue_ljy/article/details/80281803
https://www.cnblogs.com/guolintao/p/9019504.html
https://www.cnblogs.com/xuyuntao/articles/6391728.html
https://github.com/fomenyesu/egg-restapi-module-tool/blob/master/README.cn.md

ES6模版语法:

Android res文件夹解析

发表于 2018-10-06 | 分类于 移动开发

[toc]

https://blog.csdn.net/ws00801526/article/details/10449621

说明

AS中Gradle默认不创建asserts文件夹,但他的路径已经存在于main 文件夹下面了,也可通过sourceSets属性在gradle中配置工程结构
https://github.com/ShinChven/MigrateToGradle

自定义文件夹

android项目中的资源文件支持拓展:定义资源文件夹名-拓展属性,拓展属性包括以下内容

  • 语言 -en -es
  • 区域 -rCN
  • 屏幕方向 -port -land -square
  • 屏幕密度 -92dpi
  • 用户是否可以使用键盘 -keysexposed,-keyshidden
  • 默认的文字输入方法 -nokeys,-qwerty
  • 默认的非触摸导航方法 -notouch,-dpad
  • 屏幕尺寸 -324x240,-640x480 较大尺寸必须首先声明
  • 触摸屏类型 -notouch ,-finger,-stylus
  • 版本号 -V4 ,-V7

注意事项:值之间-号连接,大小写敏感,同一类型只能有一个值

valuse资源文件

文件说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
strings.xml
作用:定义字符串
定义格式:<string name="xxx">字符串值</string>
支持占用符 例子: <string name="xxx">今天%1$s,温度%2$d</string>
%1 %2---代表参数所在位置
$s,$d代表参数,s,d为参数类型
getString(R.string.xxx,"星期一",20) = 今天星期一,温度20
使用方法:资源文件中 @string/xxx
代码中 getString(R.string.xxx)
arrays.xml
作用:定义数组,可以是int,string,char
定义格式:<type-array name="xxx">
<item>数组元素值</item>
</type-array>
使用方法:资源文件中 不支持引用
代码中 type s[] = getResource.getTypeArray(R.array.xxx)
colors.xml
作用:定义颜色
定义格式:<color name="xxx">#color值</color>
使用方法:资源文件中 @color/xxx
代码中getResource.getColor(R.color.xxx) 或者
getresource.getDrawable(R.color.xxx)
dimens.xml
作用:定义尺寸大小
定义格式:<dimen name="xxx">值</dimen>
使用方法:资源文件中 @dimen/xxx
代码中 getResource.getDimension(R.dimen.xxx)
styles.xml
作用:定义试图样式
定义格式:<style name="xxx" parent="yyy">
<item name="xxx2">元素值</item>
</style>

适配API

AS的Project视图时,会有valuse与valuse-V(XX)文件夹;Android视图时,有时valuse资源文件下的xml文件会有多个,如多个strings.xml文件,其使用规则如下:

  • values: 是缺省的文件夹且最后被匹配的,它包含在value是-X中没有包含的API水平。一般缺省都使用这个文件夹
  • value-11: 针对API在11以上和13以上的,如果values-14存在的话。如果values-14不存在,则API 11以上都要使用该文件夹。另外API在11以下则无法使用该文件夹
  • 开发中只需要在VXX中指定特殊的,其他的全放在values即可

drawable文件夹

  • 作用:存放各种图片类型,不能纯数字定义文件名,另可以新建.xml文件类型 通常自定义控件样式时会在此文件夹中新建个.xml格式文件作为背景图
  • 使用方法:
1
getDrawable(R.drawable.xxx)

layout文件夹

基本使用

  • 作用:存放各种布局文件
  • 使用方法:
1
2
setcontentView(R.layout.xxx) ;
View view = LayoutInflater.from(context).inflate(R.layout.xxx,null)

建立子文件夹

  • AS中layout只能在project视图下有效,android目录下无效
  • ‘src/main/res/layout’,'src/main/res’为必写项,必须放到最后

在这个module的build.gradle文件下添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
sourceSets {
main {
res.srcDirs =
[
'src/main/res/layout/main',
'src/main/res/layout/dialog',
...
//下面两个是固定兼容写法,必须放到最后
'src/main/res/layout',
'src/main/res'
]
}
}

xml文件夹

  • 作用:存放各种xml文件,例如使用PreferenceFragment时需要在此xml文件夹中建立个preferenceFragment使用的.xml文件
  • 使用方法:
1
XmlResoutceParser xml = getResources().getXml(R.xml.xxx)

assets文件夹

  • 创建:右键new–>Folder–>AssetsFolder
  • assets目录是Android的一种特殊目录,用于放置APP所需的固定文件,且该文件被打包到APK中时,不会被编码到二进制文件
  • assets目录不会被映射到R中,因此,资源无法通过R.id方式获取,必须要通过AssetManager进行操作与获取
  • assets下可以有多级目录
  • assets目录下资源不会被二进制编码
  • 使用方法:
1
2
InputStream read =getAssets().open(R.assets.xxx)
OutputStream write = getAssets().open(R.assets.xxx)

raw文件夹

需自行创建

  • res/raw目录下的资源会被映射到R中,可以通过getResource()方法获取资源
  • res/raw下不可以有多级目录
  • res/raw不会被编码
  • 使用方法:
1
2
InputStream read = getResources().openRawResource(R.raw.xxx)
OutputStream write = getResources().openRawResource(R.raw.xxx)

anim文件夹

需自行创建

  • 作用:存放各种自定义动画格式
  • 使用方法
1
getResources().getAnimation(R.anim.xxx)

AndroidStudio代码注释及Javadoc生成

发表于 2018-10-06 | 分类于 移动开发

[toc]

https://www.jetbrains.com/help/idea/meet-intellij-idea.html

AS注释设置

新建的类自动生成的注释

File–>Settings–>Editor–>File and code Template

点击includes->File Header,修改内容为:

1
2
3
4
5
6
/**
* @author ${USER}
* @version ${VERSION}
* @description: TODO (必填)
* @date ${DATE}
*/

自定义注释模板

File–>Setting–>Editor–>LiveTemplate

  1. 新建一个Live Group
  2. 新建一个LIve Template
  3. 添加你的注释
  4. 点击Edit Variables,在Expression选择你需要方法,相当于给你的变量赋值
  5. 选择你要运用的地方
  6. 点击Apply

Javadoc文档生成

Tools->Generate JavaDoc…

  1. 设置输出路径
  2. 设置Othere command line arguments参数: -encoding utf-8 -charset utf-8支持中文
  3. 其他设置参看设置界面

Android应用坐标系及栏目

发表于 2018-10-06 | 分类于 移动开发

[toc]

http://www.jb51.net/article/96226.htm

Android应用坐标系

Android坐标系其实就是一个三维坐标,Z轴向上,X轴向右,Y轴向下。这三维坐标的点处理就能构成Android丰富的界面或者动画等效果,所以Android坐标系在整个Android界面中算是盖楼房的尺寸草图

屏幕区域划分

  • 状态栏:是指手机左上最顶上,显示中国移动、安全卫士、电量、网速等等,在手机的顶部
  • 通知栏:下拉就会出现通知栏,4G、蓝牙等设置界面
  • 标题栏:是指一个APP程序最上部的titleBar,从名字就知道它显然就是一个应用程序一个页面的标题了,例如打开QQ消息主页,最上面显示消息那一栏就是标题栏。
  • 导航栏:是手机最下面的返回,HOME,主页三个键,有些是一个按钮。

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//获取屏幕区域的宽高等尺寸获取
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
//应用程序App区域宽高等尺寸获取
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
//获取状态栏高度
Rect rect= new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rectangle.top;
//View布局区域宽高等尺寸获取
Rect rect = new Rect();
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);

ActionBar/ToolBar

  • ActionBar:Action Bar取代了传统的tittle bar和menu
  • ToolBar是替代ActionBar的控件
  • 由于ActionBar在各个安卓版本和定制Rom中的效果表现不一,导致严重的碎片化问题,ToolBar应运而生
  • ToolBar与ActionBar区别显示效果并没有区别
  • ToolBar优点:自定义视图的操作更加简单,状态栏的颜色可以调(Android 4.4以上)
  • ToolBar在 material design 也对之做了名称的定义:App bar

https://blog.csdn.net/guolin_blog/article/details/18234477
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2006.html

TitleBar

https://www.jianshu.com/p/3474a4cc7108

StatusBar

https://blog.csdn.net/qq_33689414/article/details/73330643
https://blog.csdn.net/u012102504/article/details/53406646

Navigation Bar

https://blog.csdn.net/weixin_37077539/article/details/59110273

Android手机可分为有导航栏以及没导航栏两种,一般有物理按键的机器不会带有导航栏,而没有物理按键的机器则基本会带,比如华为的手机基本都是带导航栏的

Retrofit

发表于 2018-10-06 | 分类于 移动开发

[toc]

官网说明:http://square.github.io/retrofit/

推荐教程1:https://www.jianshu.com/p/86e5cddcc753

推荐教程2:https://www.jianshu.com/p/308f3c54abdd

大名鼎鼎的Retrofit库内置了对RxJava的支持

创建Retrofit实例

1
2
3
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/")
.build();

URL注意事件:

  1. Base Ulr 必须以 /(斜线) 结束,不然会抛出一个IllegalArgumentException
  2. @Url(@GET,@POST): 不要在开始位置加 /
  3. URL类似 https://www.baidu.com?key=value 用来作为baseUrl其实是可行的,因为这个URL隐含的路径就是 /(斜线,代表根目录) ,而后面的?key=value在拼装请求时会被丢掉所以写上也没用

接口定义

1
2
3
4
public interface BlogService {
@GET("blog/{id}")
Call<ResponseBody> getBlog(@Path("id") int id);
}

注意,这里是interface不是class,所以我们是无法直接调用该方法,我们需要用Retrofit创建一个BlogService的代理对象

1
BlogService service = retrofit.create(BlogService.class);

接口调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Call<ResponseBody> call = service.getBlog(2);
// 用法和OkHttp的call如出一辙,
// 不同的是如果是Android系统回调方法执行在主线程
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
}
});

Converter

在默认情况下Retrofit只支持将HTTP的响应体转换换为ResponseBody,
即返回值都是 Call,而Converter就是Retrofit为我们提供用于将ResponseBody转换为我们想要的类型,如:

1
2
3
4
public interface BlogService {
@GET("blog/{id}")
Call<Result<Blog>> getBlog(@Path("id") int id);
}

引入Gson支持

1
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

通过GsonConverterFactory为Retrofit添加Gson支持

1
2
3
4
5
6
7
8
9
10
Gson gson = new GsonBuilder()
//配置你的Gson
.setDateFormat("yyyy-MM-dd hh:mm:ss")
.create();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
//可以接收自定义的Gson,当然也可以不传
.addConverterFactory(GsonConverterFactory.create(gson))
.build();

这样Retrofit就会使用Gson将ResponseBody转换我们想要的类型。

示例:

1
2
@POST("blog")
Call<Result<Blog>> createBlog(@Body Blog blog);

被@Body注解的的Blog将会被Gson转换成RequestBody发送到服务器。

1
2
3
4
5
6
BlogService service = retrofit.create(BlogService.class);
Blog blog = new Blog();
blog.content = "新建的Blog";
blog.title = "测试";
blog.author = "怪盗kidou";
Call<Result<Blog>> call = service.createBlog(blog);

RxJava与CallAdapter

Converter是对于Call中T的转换,而CallAdapter则可以对Call转换,这样的话Call中的Call也是可以被替换的,而返回值的类型就决定你后续的处理程序逻辑,同样Retrofit提供了多个CallAdapter,这里以RxJava的为例,用Observable代替Call:

1
2
引入RxJava支持:
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

通过RxJavaCallAdapterFactory为Retrofit添加RxJava支持:

1
2
3
4
5
6
7
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// 针对rxjava2.x
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();

接口设计:

1
2
3
4
public interface BlogService {
@POST("/blog")
Observable<Result<List<Blog>>> getBlogs();
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BlogService service = retrofit.create(BlogService.class);
service.getBlogs(1)
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<Result<List<Blog>>>() {
@Override
public void onCompleted() {
System.out.println("onCompleted");
}

@Override
public void onError(Throwable e) {
System.err.println("onError");
}

@Override
public void onNext(Result<List<Blog>> blogsResult) {
System.out.println(blogsResult);
}
});

像上面的这种情况最后我们无法获取到返回的Header和响应码的,如果我们需要这两者,提供两种方案:

  1. 用Observable<Response> 代替 Observable ,这里的Response指retrofit2.Response
  2. 用Observable<Result> 代替 Observable,这里的Result是指retrofit2.adapter.rxjava.Result,这个Result中包含了Response的实例

Rxjava和lambda语法

发表于 2018-10-06 | 分类于 移动开发

[toc]

简介

Java8 lambda表达式官网:https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

翻译:https://blog.csdn.net/future234/article/details/51919545

语法糖:也译为糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

lambda表达式其实就是实现SAM接口的语法糖。lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名类

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表

参考文章:
https://www.cnblogs.com/aoeiuv/p/5911692.html

AndroidStudio配置使用lambda

  1. 更新 Android 插件到 3.0.0(或更高版本)
  2. 针对使用(包括在源代码中或通过依赖项使用)Java 8 语言功能的每个模块,在其 build.gradle 文件中添加以下代码:
1
2
3
4
5
6
7
8
9
android {
...
// Configure only for each module that uses Java 8
// language features (either in its source code or
// through dependencies).
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

lambda表达式语法

1
2
3
4
5
6
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
  1. 当lambda表达式的参数个数只有一个,可以省略小括号
  2. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号
  3. lambda表达式可以访问给它传递的变量,访问自己内部定义的变量,同时也能访问它外部的变量。
    不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)
  4. 在lambda中,this不是指向lambda表达式产生的那个SAM对象,而是声明它的外部对象

函数式接口

  • 函数式接口:Functional Interface.
  • 定义的一个接口,接口里面必须 有且只有一个抽象方法 ,这样的接口就成为函数式接口
  • 在可以使用lambda表达式的地方,方法声明时必须包含一个函数式的接口
  • lambda表达式只能出现在目标类型为函数式接口的上下文中,意味着如果我们提供的这个接口包含一个以上的Abstract Method,那么使用lambda表达式则会报错

常见写法

替代匿名内部类

1
2
3
4
5
6
7
8
9
10
11
12
public void oldRunable() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The old runable now is using!");
}
}).start();
}

public void runable() {
new Thread(() -> System.out.println("It's a lambda function!")).start();
}

对集合进行迭代

1
2
3
4
5
6
7
8
9
10
public void iterTest() {
List<String> languages = Arrays.asList("java","scala","python");
//before java8
for(String each:languages) {
System.out.println(each);
}
//after java8
languages.forEach(x -> System.out.println(x));
languages.forEach(System.out::println);
}

用lambda表达式实现map

map函数可以说是函数式编程里最重要的一个方法了,map的作用是将一个对象变换为另外一个

1
2
3
4
public void mapTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
cost.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));
}

用lambda表达式实现map与reduce

educe与map一样,也是函数式编程里最重要的几个方法之一。。。map的作用是将一个对象变为另外一个,而reduce实现的则是将所有值合并为一个

1
2
3
4
5
public void mapReduceTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
double allCost = cost.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();
System.out.println(allCost);
}

android中MVP模式简介

发表于 2018-10-06 | 分类于 移动开发

[toc]

https://github.com/googlesamples

https://github.com/googlesamples/android-architecture

简介

  • MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器
  • Android本身就采用的是MVC(Model View Controllor)模式、其中Model指的是数据逻辑和实体模型;View指的是布局文件、Controllor指的是Activity
  • 从MVC和MVP两者结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑控制处理的角色,起着控制各业务流程的作用
  • MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控 View与Model之间的间接交互
  • 在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread中才能操作UI,所以对View与Model的切断分离是 合理的
  • Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试

具体使用

参考:

  1. https://www.jianshu.com/p/1f91cfd68d48
  2. https://github.com/LJYcoder/DevRing
  3. http://www.jcodecraeer.com/a/anzhuokaifa/2017/1020/8625.html?1508484926
  4. https://www.jianshu.com/p/364f14c76874

需要写四个部分:Model层,View层,Presenter层,接口

接口

负责“连接”MVP三层,以便方法调用、数据流动。同时也便于进行单元测试。

IView

View层接口,定义View层需实现的方法,P层通过该接口回调通知View层

1
2
3
4
5
6
public interface IMovieView {
//成功获取到电影数据
void getMovieSuccess(List<MovieRes> list, int type);
//获取电影数据失败
void getMovieFail(int status, String desc, int type);
}

IModel/IService

Model层接口,定义Model层需实现的方法,P层通过该接口调用M层获取/处理数据的方法;有些项目把这块也拆分未Service层,叫法不同而已

1
2
3
4
5
public interface IMovieMoel{
//请求正在上映的电影数据
Observable getPlayingMovie(int start, int count);
...
}

Model层/Service

实现IModel/IService接口中的方法,负责数据的获取/处理

1
2
3
4
5
6
7
8
9
public class MovieModel implements IMovieMoel{

@Override
public Observable getPlayingMovie(int start,int count) {
//提供数据源
return DevRing.httpManager().getService(MovieApiService.class).getPlayingMovie(start, count);
}
...
}

Presenter层

  • Presenter处理业务逻辑,调用M层获取数据,调用V层传递展示数据
  • Presenter持有一个IView接口,是为了能够通过View接口通知Activity进行更新界面等操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class MoviePresenter {
private IMovieView mIView;
private IMovieModel mIModel;

public MoviePresenter(IMovieView iMovieView, IMovieMoel iMovieMoel) {
mIView = iMovieView;
mIModel = iMovieModel;
}

/**
* 获取正在上映的电影
*
* @param start 请求电影的起始位置
* @param count 获取的电影数量
* @param type 类型:初始化数据INIT、刷新数据REFRESH、加载更多数据LOADMORE
*/
public void getPlayingMovie(int start, int count, final int type) {
DevRing.httpManager().commonRequest( mIModel.getPlayingMovie(start, count),
new CommonObserver<HttpResult<List<MovieRes>>>() {
@Override
public void onResult(HttpResult<List<MovieRes>> result) {
if (mIView != null) {
mIView.getMovieSuccess(result.getSubjects(), type);
}
}

@Override
public void onError(int errType, String errMessage) {
if (mIView != null) {
mIView.getMovieFail(errType, errMessage, type);
}
}
}, RxLifecycleUtil.bindUntilDestroy(mIView));
}

...

/**
* 释放引用,防止内存泄露
*/
public void destroy() {
mIView = null;
}
}

View层

实现IView接口中的方法,对获取到的数据进行展示。对应日常的Activity/Fragement类,实现Iview接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MovieActivity extends Activity implements IMovieView {
//获取电影数据成功的网络请求回调
@Override
public void getMovieSuccess(List<MovieRes> list, int type) {
//成功,对数据进行展示
....
}

//获取电影数据失败的网络请求回调
@Override
public void getMovieFail(int status, String desc, int type) {
//失败,界面上做出相应提示
...
}

...
}

或者匿名类对象关联:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mBookPresenter.onCreate();
mBookPresenter.attachView(mBookView);
}

private BookView mBookView = new BookView() {
@Override
public void onSuccess(Book mBook) {
text.setText(mBook.toString());
}

@Override
public void onError(String result) {
Toast.makeText(MainActivity.this,result, Toast.LENGTH_SHORT).show();
}
};

调用

  1. 在View层初始化时,调用Presenter层方法即可
1
2
3
4
5
6
@Override
protected void onCreate(Bundle saveInstanceState) {
...
mPresenter = new MoviePresenter(this, new MovieModel());
mPresenter.getPlayingMovie(start, mCount, type);
}
  1. 如果Presenter层持有了View层的引用,那么记得在V层销毁时,把Presenter层中对View层的引用置null,避免View层回收失败导致内存泄漏
1
2
3
4
5
6
7
8
@Override
public void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter.destroy();
mPresenter = null;
}
}

android中handler的使用

发表于 2018-10-06 | 分类于 移动开发

[toc]

简介

handler是android提供的用来更新UI的一套机制,也是一套消息处理机制,我们可以发送消息,也可以通过它处理消息

android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没有办法更新UI信息

使用

  • sendMessage
  • sendMessageDelayed
  • post(Runnable)
  • postDelayed(Runable,long)

handler.obtainMessage();
SendToTarget
拦截MEssage

原理

  1. Handler分装了消息的发送(主要包括消息发送给谁)
1
2
3
Looper
* 内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列
* Looper.Looper方法,就是一个死循环,不断的从MessageQueue去消息,如果有消息就处理消息,没有消息就阻塞
  1. MessageQueue,就是一个消息队列,可以添加消息,并处理消息
  2. Handler很简单,内部会跟Looper进行关联,也就说在Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler中发送消息,其实就是想MessageQueue队列中发送消息

总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己,MessageQueue就是一个存储消息的容器

android权限介绍

发表于 2018-10-06 | 分类于 移动开发

[toc]

https://blog.csdn.net/u013553529/article/details/68948971

简介

Android 6.0 (API level 23)中,将权限分成了两类。一类是Install权限(称之为安装时权限),另一类是Runtime权限(称之为运行时权限)

Install权限

1
2
3
4
* 在安装app时,就赋予该app的权限,即安装后立即获取到的权限
* normal和signature级别的权限都是安装时权限
* 赋予app normal和signature权限时,不会给用户提示界面,系统自动决定权限的赋予
* 对于signature权限,如果使用权限的app与声明权限的app的签名不一致,则系统拒绝赋予该signature权限

Runtime权限

1
2
3
* 指在app运行过程中,赋予app的权限,会显示明显的权限授予界面,让用户决定是否授予权限
* 如果一个app的targetSdkVersion是23及以上,那么该app所申请的所有dangerous权限都是运行时权限
* Android 6及以上的环境中,该app在运行时必须主动申请这些dangerous权限(调用requestPermissions()),否则该app没有获取到dangerous权限

RxPermissions是帮助开发者简化requestPermissions()相关的处理

官网:https://github.com/tbruyelle/RxPermissions

  1. 如果系统是Android 6之前的版本,RxPermissions返回的结果是,app请求的每个权限都被允许(granted)
  2. 使用RxPermissions申请权限,必须在Activity.onCreate()或者View.onFinishInflate()中处理
1…121314…50
行锋

行锋

496 日志
15 分类
74 标签
GitHub E-Mail
自古写字楼如青楼,不许楼里见白头
© 2015 — 2019 行锋
博客全站共229.9k字