kotlin项目 需要配置 build.gradle
如下:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 26
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.xwkotlindemo"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
productFlavors {
free {
versionName "1.0-free"
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.0.0-alpha1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
//retrofit2+rxjava2 网络请求框架
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'
compile 'com.google.code.gson:gson:2.8.0'
compile 'org.litepal.android:core:1.3.2'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
buildscript {
ext.kotlin_version = "1.0.0-rc-1036"
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
2.上面配置好后可以开始进入主题了,首先创建网络配置如下代码:
object NetConfig {
val BASEURL = "http://192.168.0.229:8080/HappyTeamService/"
}
3.创建Retofit2+Rxjava2
首先配置Retofit2以及网络拦截
这段代码是java的 因为java和kotlin可以组合使用 使用的是百度上的代码
public class HttpCommonInterceptor implements Interceptor{
private Map<String,String> mHeaderParamsMap = new HashMap<>();
Map<String, String> queryParamsMap = new HashMap<>();
Map<String, String> paramsMap = new HashMap<>();
Map<String, String> headerParamsMap = new HashMap<>();
List<String> headerLinesList = new ArrayList<>();
public HttpCommonInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Log.d("HttpCommonInterceptor","add common params");
Request oldRequest = chain.request();
// Request request = chain.request();
Headers.Builder headerBuilder = oldRequest.headers().newBuilder();
Request.Builder requestBuilder = oldRequest.newBuilder();
// 添加新的参数,添加到url 中
/* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
.newBuilder()
.scheme(oldRequest.url().scheme())
.host(oldRequest.url().host());*/
if (headerParamsMap.size() > 0) {
Iterator iterator = headerParamsMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
}
}
if (headerLinesList.size() > 0) {
for (String line: headerLinesList) {
headerBuilder.add(line);
}
requestBuilder.headers(headerBuilder.build());
}
// 新的请求
//Request.Builder requestBuilder = oldRequest.newBuilder();
requestBuilder.method(oldRequest.method(), oldRequest.body());
//添加公共参数,添加到header中
if(mHeaderParamsMap.size() > 0){
for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
requestBuilder.header(params.getKey(),params.getValue());
}
}
// process post body inject
if (paramsMap.size() > 0) {
if (canInjectIntoBody(oldRequest)) {
FormBody.Builder formBodyBuilder = new FormBody.Builder();
for(Map.Entry<String, String> entry : paramsMap.entrySet()) {
formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
}
RequestBody formBody = formBodyBuilder.build();
String postBodyString = bodyToString(oldRequest.body());
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
}
}
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
public static class Builder{
HttpCommonInterceptor mHttpCommonInterceptor;
public Builder(){
mHttpCommonInterceptor = new HttpCommonInterceptor();
}
public Builder addHeaderParams(String key, String value){
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
return this;
}
public Builder addHeaderParams(String key, int value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, float value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, long value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, double value){
return addHeaderParams(key, String.valueOf(value));
}
public HttpCommonInterceptor build(){
return mHttpCommonInterceptor;
}
}
private boolean canInjectIntoBody(Request request) {
if (request == null) {
return false;
}
if (!TextUtils.equals(request.method(), "POST")) {
return false;
}
RequestBody body = request.body();
if (body == null) {
return false;
}
MediaType mediaType = body.contentType();
if (mediaType == null) {
return false;
}
if (!TextUtils.equals(mediaType.subtype(), "x-www-form-urlencoded")) {
return false;
}
return true;
}
private static String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
}
封装一个RetrofitServiceManager
class RetrofitServiceManager {
val mRetrofit: Retrofit
val DEFAULT_TIME_OUT = 5//超时时间 5s
val DEFAULT_READ_TIME_OUT = 10
init {
val builder = OkHttpClient.Builder()
builder.connectTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
builder.writeTimeout(DEFAULT_READ_TIME_OUT.toLong(), TimeUnit.SECONDS)
builder.readTimeout(DEFAULT_READ_TIME_OUT.toLong(), TimeUnit.SECONDS)
//添加公共拦截参数
val commonInterceptor = HttpCommonInterceptor.Builder()
.addHeaderParams("palthform", "adnroid")
.addHeaderParams("userToken", "12345678912")
.addHeaderParams("userId", "123")
.build()
builder.addInterceptor(commonInterceptor)
mRetrofit = Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(NetConfig.BASEURL)
.build()
}
//单列模式
object SingletonHolder {
val INSTANCE = RetrofitServiceManager()
}
/**
* 获取对应的Service
* @param service Service 的 class
* *
* @param <T>
* *
* @return
</T> */
fun <T> create(service: Class<T>): T {
return mRetrofit.create(service)
}
/**
* 用 companion 修饰单列
*/
companion object {
/**
* 获取RetrofitServiceManager
* @return
*/
val instance: RetrofitServiceManager
get() = SingletonHolder.INSTANCE
}
}
4.设置Service
相对于单独使用Retrofit,该处返回的是Observable对象
interface ILoginService {
@POST("JsonServlet")
fun getLoginRxJava(@QueryMap params:MutableMap<String,Any>):Observable<UserBean>
}
5.RxJava Observable 订阅需要传入一个Observer对象,此处封装一个ObjectLoader
open class ObjectLoader {
protected fun <T> observe(observable: Observable<T>): Observable<T>{
return observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
接下来创建一个登录的 我返回的直接是bean类型 方便使用
class LoginLoader :ObjectLoader(){
val iLoginService:ILoginService
init {
iLoginService = RetrofitServiceManager.instance.create(ILoginService::class.java)
}
fun getLoginBean(params: MutableMap<String,Any>):Observable<UserBean>{
return observe(iLoginService.getLoginRxJava(params)).map{userBean -> userBean}
}
}
以上已经把Retofit2与Rxjava2已经配置完成。
6.接下来我们需要实现 MVP
(1).我创建model层
创建Bean
class UserBean{
var code: String? = null
var user: List<User>? = null
class User {
var age: Int = 0
var emial: String? = null
var hobby: String? = null
var password: String? = null
var phone: String? = null
var sex: String? = null
var username: String? = null
}
}
创建登录Listener接口
interface ILoginListener {
/**
* 登录成功
*/
fun onLoginSuccess()
/**
* 登录失败
*/
fun onLoginFail(message:String)
/**
* 登录错误
*/
fun onLoginError(message:String)
}
接着创建登录Model方法
interface ILoginModel {
/**
* 提取一个登录方法
* @param username 用户名
* @param password 密码
* @param loginListener 登录接口
*/
fun Login(username:String,password:String,loginListener:ILoginListener)
}
实现该ILoginModel
注意的地方主要是 val params:MutableMap<String,Any> = mutableMapOf()这里面重要的是 我刚开始运用的是 Map<String,Any> 这么写就会null报错
class LoginModel :ILoginModel{
var loginLoader:LoginLoader ? = null
var userBean:UserBean ? = null
var ErrorMsg:String ? = null
override fun Login(username: String, password: String, loginListener: ILoginListener) {
loginLoader = LoginLoader()
userBean = UserBean()
ErrorMsg = ""
if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){
loginListener.onLoginFail("输入不能为空!")
return
}
val params:MutableMap<String,Any> = mutableMapOf()
params.put("action","loginUser")
params.put("username",username)
params.put("password",password)
loginLoader!!.getLoginBean(params).subscribe(object:Observer<UserBean>{
override fun onSubscribe(d: Disposable?) {
/**
* Disposable是1.x的Subscription改名的,因为Reactive-Streams规范用这个名称,为了避免重复
* 这个回调方法是在2.0之后新添加的
* 可以使用d.dispose()方法来取消订阅
*/
}
override fun onNext(value: UserBean) {
if(value.code=="200"&& value.user!!.size>0){
loginListener.onLoginSuccess()
}else{
loginListener.onLoginFail("账号或者密码不正确")
}
}
override fun onError(e: Throwable) {
Log.e("TAG", "error message:" + e.message)
ErrorMsg = "网络出现错误!"
loginListener.onLoginError(ErrorMsg!!)
}
override fun onComplete() {
//可以干一些别的事情
Log.e("onComplete", "complete")
}
})
}
}
(2).创建view层 主要有2个方法 账号和密码
interface ILoginView {
fun getUserName():String
fun getPassword():String
}
(3).创建presenter方法 连接M层和V层
class LoginPresenter (val iLoginView:ILoginView){
val iLoginModel:ILoginModel
init {
iLoginModel = LoginModel()
}
/**
* 登录方法,建立M,V层的关系
*/
fun Login(iLoginListener: ILoginListener){
iLoginModel.Login(iLoginView.getUserName(),iLoginView.getPassword(),iLoginListener)
}
}
7.创建UI
里面包含 Activity 或者Fragment
class LoginActivity : AppCompatActivity() ,View.OnClickListener,ILoginView{
var llusername:LinearLayout?=null
var llpassword:LinearLayout?=null
var username:EditText? = null
var password:EditText? = null
var login:Button?=null
var llforgetpwd:LinearLayout?=null
var lljoinus:LinearLayout?=null
var loginPresenter:LoginPresenter?=null
var dialog: ProgressDialog? = null
var errorMsg: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.login_layout)
initView()
}
private fun initView() {
llusername = findViewById(R.id.ll_username) as LinearLayout
llpassword = findViewById(R.id.ll_password) as LinearLayout
username = findViewById(R.id.username) as EditText
password = findViewById(R.id.password) as EditText
login = findViewById(R.id.login) as Button
llforgetpwd = findViewById(R.id.ll_forget_pwd) as LinearLayout
lljoinus = findViewById(R.id.ll_join_us) as LinearLayout
llusername!!.background.alpha = 100
llpassword!!.background.alpha = 100
loginPresenter = LoginPresenter(this)
login!!.setOnClickListener(this)
llforgetpwd!!.setOnClickListener(this)
lljoinus!!.setOnClickListener(this)
}
val iloginListener = object :ILoginListener{
override fun onLoginSuccess() {
handler.sendEmptyMessage(200)
}
override fun onLoginFail(message: String) {
errorMsg = message
handler.sendEmptyMessage(1)
}
override fun onLoginError(message: String) {
errorMsg = message
handler.sendEmptyMessage(0)
}
}
val handler = object :Handler(){
override fun handleMessage(msg: Message?) {
when(msg!!.what){
0->{
if (dialog != null) {
dialog!!.dismiss()
dialog = null
}
Toast.makeText(application, "登录失败! 原因:" + errorMsg!!, Toast.LENGTH_SHORT).show()
}
1->{
if (dialog != null) {
dialog!!.dismiss()
dialog = null
}
Toast.makeText(application, "登录失败! 原因:" + errorMsg!!, Toast.LENGTH_SHORT).show()
}
200->{
if (dialog != null) {
dialog!!.dismiss()
dialog = null
}
//存储账号和密码
//saveKeepPwd(username!!.text.toString().trim { it <= ' ' }, password!!.text.toString().trim { it <= ' ' })
val intent = Intent(this@LoginActivity, MainActivity::class.java)
startActivity(intent)
finish()
}
}
}
}
override fun onClick(v: View?) {
when(v!!.id){
R.id.login->{
if(dialog==null){
dialog = ProgressDialog(this)
dialog!!.setTitle("加载中")
dialog!!.setMessage("正在加载中...")
dialog!!.setCanceledOnTouchOutside(false)
dialog!!.setCancelable(true)
dialog!!.show()
}
loginPresenter!!.Login(iloginListener)
}
R.id.ll_forget_pwd->{
}
R.id.ll_join_us->{
}
}
}
override fun getUserName(): String {
return username!!.text.toString().trim { it <= ' ' }
}
override fun getPassword(): String {
return password!!.text.toString().trim { it <= ' ' }
}
}
在这里面出现了?和 !!
? 代表的可以为null
!!代表不能为空当为空的时候就会抛出异常
还有 kotlin里面利用when else取代了java switch default,使用都差不多。
8.当需要使用 Adapter的时候 可以这么写
class ListAdapter(var context: Context?, val list: List<UserBean.User>):RecyclerView.Adapter<ListAdapter.MainViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MainViewHolder {
if (context == null) {
if (parent != null) {
context = parent.context
}
}
var v:View = LayoutInflater.from(parent?.context).inflate(R.layout.list_adapter_item,parent,false)
return MainViewHolder(v)
}
override fun getItemCount(): Int {
return list?.size!!
}
override fun onBindViewHolder(holder: MainViewHolder?, position: Int) {
//数据获取在这里
var user = list.get(position)
holder?.mtxtname?.text = "${user.username}"
holder?.mtxtcon?.text = "${user.password}"
}
class MainViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview){
var mtxtname: TextView? = null
var mtxtcon: TextView? = null
init {
mtxtname = itemview.findViewById(R.id.txt_name)
mtxtcon = itemview.findViewById(R.id.txt_con)
}
}
}
以上就是所有的代码
感谢 泓洋 的mvp理论
源代码如下
http://download.csdn.net/download/a1989214/9953125