美文网首页Android studio【idea】android版本新特性Android开发
通用的Android练习项目模板配置「常用工具类,项目结构,模板

通用的Android练习项目模板配置「常用工具类,项目结构,模板

作者: 唐_夏影 | 来源:发表于2018-12-15 14:07 被阅读19次

    为什么会有这篇文章呢,是因为我发现我以前在学习开发知识时,对代码的整理太不好了,经常是会发生以前学习过的知识,现在却找不到代码在哪里的情况,于是又要重新开始

    但如果时想要系统的去整理笔记的话,就必须要分文件夹进行管理,每个文件夹对应着不同方向的知识,而我们很多时候,每个练习项目都有着很多需要重复配置的东西

    比如常用的依赖啊,工具类,分包啊,还有基本的测试按钮,比如你想学习数据库操作,可能就会在xml布局中书写4个Button,再写上id,点击事件...基本上这些弄完,10分钟过去了

    而我接下来分享的小技巧,可能让你把原本1小时才能做完的事情,在5分钟内完成,因为我们会编写一个联系项目的模板,把重复的东西抽取出来

    项目采用Java语言,同时提供kotlin语言版本作为小彩蛋,需要说明的是,项目的开发环境是3.1.1,在3.0以下的软件运行起来需要调整,具体怎么调整我不告诉你,因为推荐升级软件

    项目源代码已经上传的Github仓库的template文件夹内了

    现在,我们创建我们的template项目

    创建项目结构

    我们创建两个module,一个是默认的app,一个是appk,一个库common

    • app用来编写Java测试代码
    • appk用来编写kotlin测试代码
    • common库用于存放一些公共的依赖,工具类
    项目结构.png

    当然,这里的app和appk并不要求百分百严格区分Java和kotlin代码,看实际情况,比如你比较多的时间是在使用Java,那么就在app里面写,偶尔也可以在里面写些kotlin,这都无所谓

    现在打开右上角的File-Prokect Structure,我们把common库的依赖添加到app和appk中,这样两个module就能使用Common里面的东西啦

    GIF.gif

    App运行库

    完成分包,配置主题,创建Menu菜单,drawable-hdpi,color,assets文件夹操作

    1)创建项目的包结构

    我们在module下创建以下包

    module分包.png

    然后,我来具体解释一下每个包的含义(其实看名字也挺清晰的了)

    • adapter 适配器包,用来存放RecyclerView等的适配器

    • app 创建自定义Application,因为后面可能配置很多第三方,而第三方的初始化建议是每个第三方单独的创建一个单例模式的类,提供一个init方法去初始化,以减少代码的量,后面会提供一个AppConfig类作为示范

    • module 业务包,用来存放我们的各种实际练习代码,这里视你的项目是用来做什么来定,假如你是实际开发,就是一个登录包,一个主页包,如图,假如该项目你是用来学习Android原生控件,那么下面就是imageview,textview这样子

      还有一个refrence包,这是用来存放你的练习草稿的,怎么说呢,你在练习的时候如果有什么需要单独提取出来测试的,你都可以在里面创建一个Activity,那个draft.txt也很好理解,就是草稿,你可以把在网上复制的代码先放到里面,后面写时可以去参考

    • net包用来存放网络请求相关的类

    • util包用来存放工具类

    • view包用来存放用到的自定义控件,可能你会有疑问了,实际开发中,view包不是都是放置在Common通用库里面的吗?是的,因为我们实际开发可能会使用组件化,多Module的开发,把view提取到Common通用库确确实实是为了让多个module来使用,但是这里我们只是练习模板项目,如果还要使用组件化那这个模板项目也就太复杂了,不符合我们当初节约时间的初衷,所以这里直接是,哪个Module的view就放在哪个module

    2)配置主题和颜色

    以前自己学习东西创建项目时,很喜欢把主题改成没有标题的,然后再到创建的Activity里面去创建几个Button,写点击事件去测试,这是多浪费时间的事情啊!

    其实我们可以使用默认的主题来解决这个问题(为什么能解决后面会说),其实默认的主题并不丑,丑的是它的颜色,所以我们到res-values包下的colors文件,修改一下它的配色

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="colorPrimary">#008577</color>
        <color name="colorPrimaryDark">#00574B</color>
        <color name="colorAccent">#D81B60</color>
    </resources>
    
    

    运行程序

    Screenshot_1544633796.png

    你看,这样就好看多了吧

    3)创建Menu文件,实现点击事件

    可能你还会觉得,默认的带标题的主题,未免有点占用我们的屏幕,是的,但是它的标题,却带给我们一个平时用的少,但是测试起来用的爽的东西,Menu

    我们在res包下创建Menu文件夹,再创建menu.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <item
            android:id="@+id/one"
            android:title="one" />
    
        <item
            android:id="@+id/two"
            android:title="two" />
    
        <item
            android:id="@+id/three"
            android:title="three" />
    
        <item
            android:id="@+id/four"
            android:title="four" />
    
        <item
            android:id="@+id/five"
            android:title="five" />
    
        <item
            android:id="@+id/six"
            android:title="six" />
        <item
            android:id="@+id/seven"
            android:title="seven" />
    
        <item
            android:id="@+id/eight"
            android:title="eight" />
    </menu>
    

    8个按钮,足够你一个Activity测试了吧,毕竟比如练习数据库操作也就是增删改查,再多的代码也不适合放在同一个Activity里了,后面我们希望看到的,就是点击右边的..,就可以弹出我们的Menu测试按钮

    menu.png

    之后我们在module-refrence包下创建JavaActiivty,将Activity作为第一启动项,编写以下代码来实现菜单的点击事件

    /**
     * Created by 舍长
     * describe:
     */
    public class JavaActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_java);
        }
    
    
        //创建菜单
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.menu, menu);
            return true;
        }
    
        //菜单选项
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int i = item.getItemId();
            switch (i) {
                //
                case R.id.one:
                    Toast.makeText(this, "one", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.two:
                    break;
                //
                case R.id.three:
                    T.s(true);
                    break;
                //
                case R.id.four:
                    Toast.makeText(this, "four", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.five:
                    Toast.makeText(this, "five", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.six:
                    Toast.makeText(this, "six", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.seven:
                    Toast.makeText(this, "seven", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.eight:
                    Toast.makeText(this, "eight", Toast.LENGTH_SHORT).show();
                    break;
    
            }
            return true;
        }
    }
    
    

    运行程序

    menu

    ok,我们已经完美的完成了,可能你会觉得,这样代码量也不少啊,是的,但是它在所有Activity里面的代码都是一样的啊!

    我们需要在哪个Activity用,就直接复制粘贴就可以了,其实也不推荐复制粘贴的方法,我们有更高效的,使用软件自己的代码模板功能,接下来演示一下该方法

    使用代码模板制作菜单.gif

    代码模板具体的制作方法可以查看慕课网的教程的第三章,第二节,传送门

    另外我们还可以添加一个ButterKnife来节约我们findId控件的代码,但是实际项目开发中不建议使用,因为实际上我遇到过使用该框架后与其他东西的冲突,gradle版本也会对它造成影响,集成教程

    4)创建drawable-hdpi,color,asstes文件夹

    为什么我们要在res下创建drawable-hdpi包呢,因为放置在该文件夹里面的图片,系统会帮助你进行一些处理,当你不使用图片加载框架的时候,放置在ImageView有可能因为图片过大而导致内存溢出,程序崩溃

    而放置在drawable-hdpi下的图片不会,还有一个原因就是保持代码的整洁,我通常是.xml结尾的,例如选择器,使用shape制作的图片,vector图片就放置在drawable,而其它能直接看到的格式的,如,png,jpg,就会放置在drawable-hdpi

    图片分包.png

    而上面的颜色选择color包可能会在某些场景下用,比如使用BottomNavigationView的时候

    最后是我们的assets文件夹,用来存放如字体,本地调试html页面等,在源码里的Refrence包下会有调用字体文件的查考代码

    Common通用库

    该库用来存放我们练习中几乎必备的工具类和相关的依赖,我们把这些东西提取在Common包里面,让app添加它,这样app就不用显示过多的依赖,显得比较简洁,而且我们的appk同样可以使用它

    1)Log工具类

    我们在common库中创建util文件夹,然后创建L日志打印工具类,简化我们后面的日志操作

    /**
     * Created by 舍长 on 2018/12/14
     * describe: 日志工具类
     */
    public class L {
        public void d(String msg) {
            Log.d("helloWorld", msg);
        }
    }
    
    

    后面就可以直接L.d使用啦

         //日志工具类
                case R.id.one:
                    L.d("打印d级别的Log请求,Log是helloWorld");
                    Toast.makeText(this, "one", Toast.LENGTH_SHORT).show();
                    break;
    
    2)Toast工具类

    我们的Toast工具类也是想放到Common包下的,但是它的使用需要获取对应的context,而如果我们的参数要传入两个参数,1是传入Context,2是要打印的内容的话

    这样就体现不出工具类的易用性了,所以我们应该创建一个全局的Context,这在组件化的开发中也很常见,实际操作并不复杂,我们来看一下

    我们的Common库中创建app包,在该包下创建BaseApp类,让该类继承于Application,然后我们提供一个getContext()方法来返回Context独享

    /**
     * Created by 舍长 on 2018/12/14
     * describe:项目基础Application
     */
    public class BaseApp extends Application {
    
        private static Context context;
    
        //我们也可以在这里初始化一些项目通用的东西
        //比如查看数据库数据文件的Stetho
        //这里就不演示了,详细集成可以查看我的另一篇文章
        //https://www.jianshu.com/p/6a3b0ae4aeb4
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        //创建一个静态的方法,以便获取context对象
        public static Context getContext() {
            return context;
        }
    }
    

    接着写我们的Toast工具类

    /**
     * Created by 舍长 on 2018/12/14
     * describe:
     */
    public class T {
        /**
         * 弹出短吐司
         */
        public static void s(Object object) {
            //这里的参数为object而不是String的目的是为了能传入更多类型的数据
            //而不管传入什么类型,我们都把它转成String类型,这样就使用起来就比较方便了,不用再进行toString操作
            //而我们如果传进来,不是数据类型,而是自己定义的类,就会打印出对象的toString方法
            String s = object.toString();
            Toast.makeText(BaseApp.getContext(), "" + s, Toast.LENGTH_SHORT).show();
        }
    }
    

    我们使用BaseApp.getContext()方法来获取Context,但是到现在为止,其实BaseApp和我们的App程序是没有任何关系的,我们当然也可以直接到AppModule的权限菜单引用它

    但是这样后面我们要在自定义的Application配置一些东西的话,就得返回到Common库,有点麻烦。所以我们选择创建AppModule自己的自定义Application类,App

    然后让该类去去继承与BaseApp,最后在AppModule的权限菜单应用的,就是我们AppModule里面自己的Appilication类,这样就即可以让Common库有Context对象,又方便我们后面Application的使用

    /**
     * Created by 舍长 on 2018/12/14
     * describe:自定义Application
     */
    public class App extends BaseApp{
        @Override
        public void onCreate() {
            super.onCreate();
        }
    }
    
    

    在权限菜单中去引用

     <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.tonjies.template">
    
        <application
            android:name=".app.App"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
    
            </activity>
    
            <!--菜单Activity-->
            <activity android:name=".module.refrence.JavaActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    之后就可以在我们之间创建的,refrence包下的JavaActivity中去使用啦

    
      //菜单选项
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int i = item.getItemId();
            switch (i) {
                //日志工具类
                case R.id.one:
                    L.d("打印d级别的Log请求,Log是helloWorld");
    //                L.d(true);//经过类型判断的版本
                    Toast.makeText(this, "one", Toast.LENGTH_SHORT).show();
                    break;
                //吐司工具类
                case R.id.two:
                    T.s("你好,世界");
                    break;
                //吐司工具类
                case R.id.three:
                    T.s(true);
                    break;
                //
                case R.id.four:
                    Toast.makeText(this, "four", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.five:
                    Toast.makeText(this, "five", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.six:
                    Toast.makeText(this, "six", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.seven:
                    Toast.makeText(this, "seven", Toast.LENGTH_SHORT).show();
                    break;
                //
                case R.id.eight:
                    Toast.makeText(this, "eight", Toast.LENGTH_SHORT).show();
                    break;
    
            }
            return true;
        }
    

    其实我们的L日志工具类也可以像我们的吐司工具类一样加入类型转换操作

    /**
     * Created by 舍长 on 2018/12/14
     * describe: 日志工具类
     */
    public class L {
        //普通版
        public static void d(String msg) {
            Log.d("helloWorld", msg);
        }
    
        //进行类型判断
        public static void d(Object msg) {
            String string = msg.toString();
            Log.d("helloWorld", string);
        }
    }
    

    到这里,工具类部分举例子结束,除了这两个常用的,我们还可以在工具类中加入SharedPreferences啊,获取EditView的值,随机数,设置字体,等工具类,在源码中我会把几个工具类一并补上,作为本篇文章的小彩蛋

    3)添加常用依赖

    这里需要注意的是,3.0以上后,AndroidStudio添加依赖推荐使用api和implementation和替代compile,不然build时就会报红(虽然还是可以运行)

    implementation和api的区别在于,implementation用于运行Module,api用于库添加依赖,什么意思呢,就是如果你在Common使用implementation来添加依赖,那么你的AppModule是检测不到你添加的依赖的

    换句话来说,implementation只能是当它自己的范围使用,不管你是库Module还是运行Module

    接下来我们在Common的budile.gradle下添加这几个依赖

    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
         //Anko框架,用于kotlin开发扩展
        api "org.jetbrains.anko:anko-commons:0.10.7"
            
        //圆形处理框架
        api 'de.hdodenhof:circleimageview:2.2.0'
    
        //    材料设计
        api 'com.android.support:design:28.0.0'
    
        // Retrofit库
        api 'com.squareup.retrofit2:retrofit:2.4.0'
        api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'    // 此处一定要注意使用RxJava2的版本
        api 'com.squareup.retrofit2:converter-gson:2.4.0'    // 支持Gson解析
    
        // Okhttp库
        api 'com.squareup.okhttp3:okhttp:3.11.0'
        api 'com.squareup.okhttp3:logging-interceptor:3.11.0'
    
        // 支持Gson解析
        api 'com.squareup.retrofit2:converter-gson:2.4.0'
    
        //    RxJava
        api 'io.reactivex.rxjava2:rxjava:2.1.7'
        api 'io.reactivex.rxjava2:rxandroid:2.0.1'
    
        //    图片加载框架
        api 'com.github.bumptech.glide:glide:4.7.1'
    
        // 卡片布局
        api 'com.android.support:cardview-v7:28.0.0'
    
    
        implementation 'com.android.support:appcompat-v7:28.0.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
        api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    }
    repositories {
        mavenCentral()
    }
    

    除了上述封装的

    实际练习代码的分类

    1)笔记库的搭建

    有了上面的项目模板,后面我们需要的话,就可以直接复制,粘贴就可以直接上手学习了,但是我们的Android开发的内容很多,显然不是一个项目能放得下的

    所以根据学习内容的不同,我大致将它们分为以下内容,进而我们可以为不同的练习内容设置不同的项目文件名

    开发内容 项目英文名 解释
    Java基础 java 这里用IDEA
    kotlin基础 kotlin 这里用IDEA
    Android架构,开发规范 framework 如Mvp,mvc,代码抽取
    Android控件 materialDesign Android原生控件,和原生有关的界面操作
    四大组件 unit 包括Fragment也放在这里
    数据库存储 data 数据库框框架,数据库操作
    Android混合开发 mixed 与H5的交互,ndk开发
    开源库 library 比较小的UI库,比如PickerView
    主流框架 frame 如RxJava,Dagger等
    第三方服务 third 友盟,腾讯bugly
    业务代码 profession 例如多语言切换
    系统交互 system 如蓝牙,相机,通知栏
    Android安全与适配 safety 系统适配方案
    你自己的练习项目1
    你自己的练习项目2

    大致就是这样,我们复制以上数量的项目文件夹,更改完名字后,我们的笔记库到这里就结束了,也许整个过程是稍显复杂,但是我们只要制作一次

    后面我们需要找代码就方便很多,还有的好处就是如果你上次在某个方面学习到一半,有其他的事情,你下次可以很快的找到,继续学习

    上面可能你会有个疑问,开源库和主流框架的区别,其实本质上是没有区别,但是我去区分它们的标准是,它们是否极其重要,不可替代的,极其重要的,如RxJava,就把它归纳到框架里面

    而其它的,像提供某个UI控件的库,使用的少,我们可以找到替代的,甚至我们可以自己写一个的,就会被归纳到库library里面

    2)配合笔记软件

    上面制作的笔记目录,不一定适合你,实际上你可以使用笔记软件,石墨文档制作属于你自己的练习项目名称目录

    笔记目录.png

    而有一些笔记,也是使用笔记软件记录比较合适,简单来说就是,你的文字笔记和你的练习代码仓库的目录是一致的,不过需要注意的是,文字笔记和我们的练习代码仓库一样,不同类别的笔记是重新创建新的笔记来写的

    这是因为石墨文档如果你这是同一份文档写的内容太多就会卡,这里我把我的总目录文档发现出来作为参考,传送门

    不过不同类别的文档都会被放置在Android笔记的文件夹中

    笔记文件夹.png

    好了,本篇文章就到这里了,老实说,这是我写的30篇文章依赖感觉最累的一次,因为涉及的东西不难,但是很多,是让很累,但是本篇文章基本都是干货,实际运用中,能节约你大量配置项目的时间

    如果本篇文章对你有用,希望能给个喜欢,这对我来说是种很好的鼓励

    理直气壮

    相关文章

      网友评论

        本文标题:通用的Android练习项目模板配置「常用工具类,项目结构,模板

        本文链接:https://www.haomeiwen.com/subject/fvhahqtx.html