1.首先将这个项目的BaseActivity源码拷贝过来。

/*
* Copyright 2017 GcsSloop
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Last modified 2017-03-11 22:24:54
*
* GitHub: https://github.com/GcsSloop
* Website: http://www.gcssloop.com
* Weibo: http://weibo.com/GcsSloop
*/ package com.gcssloop.diycode.base.app; import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast; import com.gcssloop.diycode.R;
import com.gcssloop.diycode.hackpatch.IMMLeaks;
import com.gcssloop.diycode_sdk.api.Diycode; import java.io.Serializable; public abstract class BaseActivity extends AppCompatActivity { protected Diycode mDiycode;//项目本身的api提供的一个调用类
protected ViewHolder mViewHolder;
private Toast mToast; @TargetApi(Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDiycode = Diycode.getSingleInstance();
mViewHolder = new ViewHolder(getLayoutInflater(), null, getLayoutId());
setContentView(mViewHolder.getRootView());
IMMLeaks.fixFocusedViewLeak(this.getApplication()); // 修复 InputMethodManager 引发的内存泄漏
initActionBar(mViewHolder);
initDatas();
initViews(mViewHolder, mViewHolder.getRootView());
} @LayoutRes
protected abstract int getLayoutId(); /**
* 初始化数据,调用位置在 initViews 之前
*/
protected void initDatas() {
} /**
* 初始化 View, 调用位置在 initDatas 之后
*/
protected abstract void initViews(ViewHolder holder, View root); // 初始化 ActiobBar
private void initActionBar(ViewHolder holder) {
Toolbar toolbar = holder.get(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
} // 默认点击左上角是结束当前 Activity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
} public ViewHolder getViewHolder() {
return mViewHolder;
} /**
* 发出一个短Toast
*
* @param text 内容
*/
public void toastShort(String text) {
toast(text, Toast.LENGTH_SHORT);
} /**
* 发出一个长toast提醒
*
* @param text 内容
*/
public void toastLong(String text) {
toast(text, Toast.LENGTH_LONG);
} private void toast(final String text, final int duration) {
if (!TextUtils.isEmpty(text)) {
runOnUiThread(new Runnable() { @Override
public void run() {
if (mToast == null) {
mToast = Toast.makeText(getApplicationContext(), text, duration);
} else {
mToast.setText(text);
mToast.setDuration(duration);
}
mToast.show();
}
});
}
} protected void openActivity(Class<?> cls) {
openActivity(this, cls);
} public static void openActivity(Context context, Class<?> cls) {
Intent intent = new Intent(context, cls);
context.startActivity(intent);
} /**
* 打开 Activity 的同时传递一个数据
*/
protected <V extends Serializable> void openActivity(Class<?> cls, String key, V value) {
openActivity(this, cls, key, value);
} /**
* 打开 Activity 的同时传递一个数据
*/
public <V extends Serializable> void openActivity(Context context, Class<?> cls, String key, V value) {
Intent intent = new Intent(context, cls);
intent.putExtra(key, value);
context.startActivity(intent);
} }

 

  2.Diycode是项目本身的api提供的一个调用类。放在module中,名字为:diycode-sdk,应该就是为了方便开发客户端提供的一个API了,里面又是一大坨,单单这个类就有一千行,很多逻辑函数,不过现在先不研究。

  3.ViewHolder是什么东西呢?

   ==>其实就是性能优化,这里是自己创建的一个类。放在和BaseActivity同一级下,所以说这个东西应该和BaseActivity一样,经常使用,以前也只是看到别人用,就自己用一下,不懂得其中真正的含义。

  网上搜了一篇文章:listview加载性能优化ViewHolder

    这个项目的ViewHolder源码是这样的:

/*
* Copyright 2017 GcsSloop
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Last modified 2017-03-11 22:24:54
*
* GitHub: https://github.com/GcsSloop
* Website: http://www.gcssloop.com
* Weibo: http://weibo.com/GcsSloop
*/ package com.gcssloop.diycode.base.app; import android.content.Context;
import android.support.annotation.NonNull;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.gcssloop.diycode_sdk.log.Logger; public class ViewHolder { private SparseArray<View> mViews;
private View mRootView; public ViewHolder(LayoutInflater inflater, ViewGroup parent, int layoutId) {
this.mViews = new SparseArray<View>();
mRootView = inflater.inflate(layoutId, parent, false);
} /**
* 通过View的id来获取子View
*
* @param resId view的id
* @param <T> 泛型
* @return 子View
*/
public <T extends View> T get(int resId) {
View view = mViews.get(resId);
//如果该View没有缓存过,则查找View并缓存
if (view == null) {
view = mRootView.findViewById(resId);
mViews.put(resId, view);
}
if (view == null){
Logger.e("View == null");
}
return (T) view;
} /**
* 获取布局View
*
* @return 布局View
*/
public View getRootView() {
return mRootView;
} /**
* 设置文本
*
* @param res_id view 的 id
* @param text 文本内容
* @return 是否成功
*/
public boolean setText(CharSequence text, @NonNull int res_id) {
try {
TextView textView = get(res_id);
textView.setText(text);
return true;
} catch (Exception e) {
return false;
}
} public boolean setText(@NonNull int res_id, CharSequence text) {
return setText(text, res_id);
} public void loadImage(Context context, String url, int res_id) {
ImageView imageView = get(res_id);
String url2 = url;
if (url.contains("diycode"))
url2 = url.replace("large_avatar", "avatar");
Glide.with(context).load(url2).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView);
} /**
* 设置监听器
*
* @param l 监听器
* @param ids view 的 id
*/
public void setOnClickListener(View.OnClickListener l, int... ids) {
if (ids == null) {
return;
}
for (int id : ids) {
get(id).setOnClickListener(l);
}
}
}

  下面分析一下:

    (1)有一个私有成员变量。private SparseArray<View> mViews;

      了解一下SpareseArray

      类似一个容器,可以装一些视图,并且这个类方便使用,性能也很棒。

    (2)然后是ViewHolder构造函数,参数分别为LayoutInflater inflater,ViewGroup parent,Int layoutId.现在仔细了解一下这几个参数吧。

      ①LayoutInflater是什么东西呢?==>主要就是将xml转换成一个View对象,动态创建布局。

       inflate方法有三个参数,分别是resource==>布局的资源id,root==>填充的根视图,attachToRoot==>是否将载入的视图绑定到根视图。

      ②View与ViewGroup有什么区别?==>View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的。

      ③LayoutId其实就是自己项目中R.id.***,就是inflate中的布局的资源的id。

    (3)通过view的id来获取子View    

 /**
* 通过View的id来获取子View
*
* @param resId view的id
* @param <T> 泛型
* @return 子View
*/
public <T extends View> T get(int resId) {
View view = mViews.get(resId);
//如果该View没有缓存过,则查找View并缓存
if (view == null) {
view = mRootView.findViewById(resId);
mViews.put(resId, view);
}
if (view == null){
Logger.e("View == null");
}
return (T) view;
}

      ①<T extends View>是一个类型,如何理解这个泛型呢?==>限制了返回的T类,必须是View的子类。

      ②这里用到了一个Logger,日志类,直接拷贝一下,这个东西也是为了方便调试的。基本上每个项目都会用到的。  

/*
* Copyright 2017 GcsSloop
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Last modified 2017-03-10 00:33:05
*
* GitHub: https://github.com/GcsSloop
* Website: http://www.gcssloop.com
* Weibo: http://weibo.com/GcsSloop
*/ package com.gcssloop.diycode_sdk.log; import android.support.annotation.NonNull;
import android.util.Log; public class Logger { private static String DEFAULT_TAG = "GCS-LOG"; private static Config mConfig; private Logger() { } public static Config init() {
mConfig = new Config(DEFAULT_TAG);
return mConfig;
} public static Config init(@NonNull String tag) {
mConfig = new Config(tag);
return mConfig;
} public static void v(String message) {
log(Config.LEVEL_VERBOSE, mConfig.getTag(), message);
} public static void d(String message) {
log(Config.LEVEL_DEBUG, mConfig.getTag(), message);
} public static void i(String message) {
log(Config.LEVEL_INFO, mConfig.getTag(), message);
} public static void w(String message) {
log(Config.LEVEL_WARN, mConfig.getTag(), message);
} public static void e(String message) {
log(Config.LEVEL_ERROR, mConfig.getTag(), message);
} public static void v(String tag, String message) {
log(Config.LEVEL_VERBOSE, tag, message);
} public static void d(String tag, String message) {
log(Config.LEVEL_DEBUG, tag, message);
} public static void i(String tag, String message) {
log(Config.LEVEL_INFO, tag, message);
} public static void w(String tag, String message) {
log(Config.LEVEL_WARN, tag, message);
} public static void e(String tag, String message) {
log(Config.LEVEL_ERROR, tag, message);
} private static void log(int level, String tag, String message) {
if (mConfig.getLevel() == Config.LEVEL_NONE) {
return;
} if (level < mConfig.getLevel()) {
return;
} switch (level) {
case Config.LEVEL_VERBOSE:
Log.v(tag, message);
break;
case Config.LEVEL_DEBUG:
Log.d(tag, message);
break;
case Config.LEVEL_INFO:
Log.i(tag, message);
break;
case Config.LEVEL_WARN:
Log.w(tag, message);
break;
case Config.LEVEL_ERROR:
Log.e(tag, message);
break;
} }
}

            Logger类中有定义一个Config类,这是在diycode_sdk里面的,先看看定义吧。

/*
* Copyright 2017 GcsSloop
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Last modified 2017-03-10 00:33:05
*
* GitHub: https://github.com/GcsSloop
* Website: http://www.gcssloop.com
* Weibo: http://weibo.com/GcsSloop
*/ package com.gcssloop.diycode_sdk.log; import android.support.annotation.NonNull; public class Config { public static final int LEVEL_NONE = 0;
public static final int LEVEL_FULL = 1; public static final int LEVEL_VERBOSE = 2;
public static final int LEVEL_DEBUG = 3;
public static final int LEVEL_INFO = 4;
public static final int LEVEL_WARN = 5;
public static final int LEVEL_ERROR = 6;
public static final int LEVEL_ASSERT = 7; private String tag;
private int level; public Config(String tag) {
this.tag = tag;
level = LEVEL_FULL;
} public Config setLevel(@NonNull int level){
this.level = level;
return this;
} public int getLevel() {
return level;
} public String getTag() {
return tag;
}
}

            感觉像一个Bean类,很简单的一个类,定义了7个静态整型常量,1,2,3,4,5,6,7,应该是日志的等级,分为7个模式吧。

    (4)有注意到有些变量前面有@NonNull注解,不知道什么意思。==>指明一个参数,字段或者方法的返回值不可以为NULL。

      (5)然后在ViewHolder中提供了setText给TextView。方式很简单,就是先通过id得到这个TextView,然后setText即可。

    (6)然后在ViewHolder中提供了一个loadImage方法。比较复杂,贴一下源代码。   

public void loadImage(Context context, String url, int res_id) {
ImageView imageView = get(res_id);
String url2 = url;
if (url.contains("diycode"))
url2 = url.replace("large_avatar", "avatar");
Glide.with(context).load(url2).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView);
}

      ①首先也是通过id得到这个imageView。

      ②这里有一个Glide类。不知道这个图片加载库怎么用?

      

    (7)最后设置了一个监听器。两个参数:View.OnClickListener l,int... ids  ==>省略号是什么意思?==>类似一个数组吧(而且事先不知道长度呢!)

  4.@TargetApi(Build.VERSION_CODES.KITKAT)在onCreate的前面声明,这东西起什么作用呢? ==>使用高编译版本的代码,为了通用性兼容运行此代码的低版本平台,要求程序员做出区分对待的加载。         

  5.在BaseActivity中的onCreate函数中,通过Diycode的SDK中获取单例类。这里了解一下什么是单例模式。==>保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  6.这里谈一下onCreate函数中的setContentView(view)

    ==>默认Activity中放入我们的xml或者Java控件是通过setContentView方法来操作的,当调用了setContentView所有的控件就得到了显示。

  7.如何解决InputMethodManager造成的内存泄漏问题?

   看一下这篇文章。

    

  8.onCreate函数中有一个初始化ActionBar,就是初始化标题栏的意思。

    ToolBar代替Actionbar在AppCompatActivity的使用

    这里解释一下:

    (1)actionBar.setDisplayHomeAsUpEnabled(true)==>给左上角图标的左边加上一个返回的图标。对应                   ActionBar.DISPLAY_HOME_AS_UP。

     (2)actionBar.setDisplayShowHomeEnabled(true) //使左上角图标是否显示,如果设成false,则没有程序图标,仅仅就个标题,否则,显示应用程序图标,对应id为android.R.id.home,对应ActionBar.DISPLAY_SHOW_HOME

    (3)actionBar.setDisplayShowCustomEnabled(true) // 使自定义的普通View能在title栏显示,即actionBar.setCustomView能起作用,对应ActionBar.DISPLAY_SHOW_CUSTOM

    (4)actionBar.setDisplayShowTitleEnabled(true) //对应ActionBar.DISPLAY_SHOW_TITLE。

    (5)其中setHomeButtonEnabled和setDisplayShowHomeEnabled共同起作用,如果setHomeButtonEnabled设成false,即使setDisplayShowHomeEnabled设成true,图标也不能点击。

  9.在BaseActivity中有一个toast函数,采用了一个runOnUiThread(new Runnable(){里面复写一个run方法即可})

    代码参考一下了:  

private void toast(final String text, final int duration) {
if (!TextUtils.isEmpty(text)) {
runOnUiThread(new Runnable() { @Override
public void run() {
if (mToast == null) {
mToast = Toast.makeText(getApplicationContext(), text, duration);
} else {
mToast.setText(text);
mToast.setDuration(duration);
}
mToast.show();
}
});
}
}

    不了解runOnUiThread?==>runOnUiThread更新主线程。

  

  10.打开一个活动,在BaseActivity中,定义一个方法,点击某个东西,跳转到另外一个活动。

 protected void openActivity(Class<?> cls) {
openActivity(this, cls);
} public static void openActivity(Context context, Class<?> cls) {
Intent intent = new Intent(context, cls);
context.startActivity(intent);
}

  11.打开一个活动的同时传递一个数据

 /**
* 打开 Activity 的同时传递一个数据
*/
protected <V extends Serializable> void openActivity(Class<?> cls, String key, V value) {
openActivity(this, cls, key, value);
} /**
* 打开 Activity 的同时传递一个数据
*/
public <V extends Serializable> void openActivity(Context context, Class<?> cls, String key, V value) {
Intent intent = new Intent(context, cls);
intent.putExtra(key, value);
context.startActivity(intent);
}

  总结一下:

  1.这个BaseActivity应该指的是大部分通用的一个活动,左上角是一个返回的图标,右上角自定义的一个导航栏。

  2.然后这个BaseActivity提供了一个toast支持,支持长toast或者短toast,而且是采用runOnUiThread更新主线程的方式。所以不会阻塞的。

  3.这个BaseActivity中有自定义ViewHolder,加强了性能。里面可以有TextView,ImageView,还可以设置监听器给每一个view。

  4.这个BaseActivity存放了一个关键的类,Diycode可以方便地调用API,获取后端数据的关键。

  5.有一个抽象函数initViews(ViewHolder,View root),那么在继承这个BaseActivity中就可以执行了。

  6.最后定义了2个重载函数,作用就是可以跳转到另外一个活动,传数据或者不传数据。

DiyCode开源项目 BaseActivity 分析的更多相关文章

  1. Diycode开源项目 BaseApplication分析+LeakCanary第三方+CrashHandler自定义异常处理

    1.BaseApplication整个应用的开始 1.1.看一下代码 /* * Copyright 2017 GcsSloop * * Licensed under the Apache Licens ...

  2. Diycode开源项目 MainActivity分析

    1.分析MainActivity整体结构 1.1.首先看一下这个界面的整体效果. 1.2.活动源代码如下 /* * Copyright 2017 GcsSloop * * Licensed under ...

  3. DiyCode开源项目 TopicActivity 分析

    1.首先看看TopActivity效果.    2.TopicActivity是一个继承BaseActivity的.前面分析过BaseActivity了.主要有一个标题栏,有返回的图标. 3.贴一下T ...

  4. Diycode开源项目 ImageActivity分析

    1.首先看一下效果 1.1做成了一个GIF 1.2.我用格式工厂有点问题,大小无法调到手机这样的大小,目前还没有解决方案. 1.3.网上有免费的MP4->GIF,参考一下这个网站吧. 1.4.讲 ...

  5. Diycode开源项目 TopicContentActivity分析

    1.效果预览以及布局分析 1.1.实际效果预览 左侧话题列表的布局是通过TopicProvider来实现的,所以当初分析话题列表就没有看到布局. 这里的话题内容不是一个ListView,故要自己布局. ...

  6. Diycode开源项目 LoginActivity分析

    1.首先看一下效果 1.1.预览一下真实页面 1.2.分析一下: 要求输入Email或者用户名,点击编辑框,弹出键盘,默认先进入输入Email或用户名编辑框. 点击密码后,密码字样网上浮动一段距离,E ...

  7. DiyCode开源项目 AboutActivity分析

    1.首先看一下效果 这是手机上显示的效果: 1.1首先是一个标题栏,左侧一个左箭头,然后一个图标. 1.2然后下方是一个可以滑动的页面. 1.3分成了7个部分. 1.4DiyCode的图标. 1.5然 ...

  8. Diycode开源项目 UserActivity分析

    1.效果预览 1.1.实际界面预览 1.2. 这是MainActivity中的代码 这里执行了跳转到自己的用户界面的功能. 1.3.点击头像或者用户名跳转到别人的页面 UserActivity的结构由 ...

  9. Diycode开源项目 SettingActivity分析

    1.整体效果预览及布局分析 1.1.设置界面预览 1.2.主体对应关系 注意这里的线条用ImageView来实现 有一个TextView是检查更新,默认隐藏,具体出现时间还得之后确认. 最后一个Lin ...

随机推荐

  1. Xcode Ghost

    Xcode Ghost,是一种手机病毒,主要通过非官方下载的 Xcode 传播,能够在开发过程中通过 CoreService 库文件进行感染,使编译出的 App 被注入第三方的代码,向指定网站上传用户 ...

  2. 实现一个Promise.all

    用js自己实现一个Promise.all let promiseAll = (promises) => { return new Promise((resolve, reject) => ...

  3. koa源码分析

    最近项目要使用koa,所以提前学习一下,顺便看了koa框架的源码. 注:源码是koa2.x koa的源码很简洁,关键代码只有4个文件,当然还包括一些依赖npm包 const Koa = require ...

  4. TX Text Control X10独家揭秘之使用对象作为数据源

    文档处理控件TX Text Control即将发布的X10版本,将升级重点还是放到了其比较优势的流式布局报表设计和生成上.慧都获得了来自其开发商Text Control GmbH公司的一手资料,迫不及 ...

  5. Google pieCharts的学习

    在公司项目开发过程中, 尤其是在网站的开发过程中,用到很多的前端的插件,在这里, 我简单介绍下近期Google pieCharts的是使用方法 https://developers.google.co ...

  6. Mantis-1.3.3 (Ubuntu 16.04)

    平台: Ubuntu 类型: 虚拟机镜像 软件包: mantis-1.3.3 bug tracking commercial devops mantis open-source project man ...

  7. Spring Boot : Swagger 2

    每次修改完代码需要找原本的API时楼主的内心是痛苦的,因为一般情况下都找不到,需要重新写一份.如果使用Swagger的话,只要加几个注解就可以实时生成最新的在线API文档,而且不仅仅是文档,同时支持A ...

  8. 在 Windows下用 Visual Studio 编译 OpenSSL 1.1.0

    到OpenSSL官方网站下载OpenSSL源代码包 1.下载 openssl-1.1.0.tar.gz 2.安装 ActivePerl, 可以到http://www.activestate.com/a ...

  9. StackOverflow之旅<2>------{HashMap和Hashtable的区别}

    问题 在Java中HashMap和Hashtable的区别? 哪一个对于多线程应用程序更好? 回答 Hashtable是同步的,加了synchronized锁,而HashMap不是.没有加synchr ...

  10. js 获取时间戳 登陆验证码生成要加时间戳

    JavaScript 获取当前时间戳,登陆验证码生成要加时间戳,防止存在session不重新请求第一种方法: var timestamp = Date.parse(new Date()); 结果:12 ...