当前位置: 代码迷 >> 综合 >> DiyCode开源项目 BaseActivity 分析
  详细解决方案

DiyCode开源项目 BaseActivity 分析

热度:7   发布时间:2024-01-21 05:27:42.0

  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)@Overrideprotected 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());}@LayoutResprotected abstract int getLayoutId();/*** 初始化数据,调用位置在 initViews 之前*/protected void initDatas() {}/*** 初始化 View, 调用位置在 initDatas 之后*/protected abstract void initViews(ViewHolder holder, View root);// 初始化 ActiobBarprivate 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
 @Overridepublic 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() {@Overridepublic 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);}}
View Code

 

  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);}} }
View Code

  下面分析一下:

    (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;}
View Code

      ①<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;}} }
View Code

            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;} }
View Code

            感觉像一个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);}
View Code

 

      ①首先也是通过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() {@Overridepublic void run() {if (mToast == null) {mToast = Toast.makeText(getApplicationContext(), text, duration);} else {mToast.setText(text);mToast.setDuration(duration);}mToast.show();}});}}
View Code

 

    不了解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);}
View Code

 

 

  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);}
View Code

 

 

   总结一下:

  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个重载函数,作用就是可以跳转到另外一个活动,传数据或者不传数据。

 

 

转载于:https://www.cnblogs.com/Jason-Jan/p/7831925.html