gpt4 book ai didi

从头开始,手写android应用框架(一)

转载 作者:我是一只小鸟 更新时间:2023-03-30 22:33:23 28 4
gpt4 key购买 nike

前言 。

搭建android项目框架前,我们需要先定义要框架的结构,因为android框架本身的结构就很复杂,如果一开始没定义好结构,那么后续的使用就会事倍功半.

结构如下:

com.kiba.framework 。

——activity 存储所有的活动 。

——base 存储baseActivity 。

——fragment存储所有的Fragment 。

  ——base 存储baseFragment 。

——service存储所有的service 。

——utils存储所有的工具类 。

——dto存储所有的传入传出实体 。

——model存储所有的实体类 。

——model_db存储所有的数据库实体类(框架使用ormlit) 。

创建项目 。

我们先创建一个项目,File—New—New Project,选择BasicActivity.

然后创建一个utils文件夹.

添加LogUtils,DateUtils,DecimalUtil文件,就是简单的日志输出,日期,字符串工具。(写法很多,可以上网任意搜索).

然后创建一个异常捕获文件——CrashExceptionHandler,用于输入未捕获异常日志(写法很多,可以上网任意搜索).

然后打开app下的gradle,引入我们常用的包.

网络请求:okhttp.

json处理:gson和fastjson.

黄油刀注解:ButterKnife.

内置数据库管理:ormlite.

权限请求:rxpermissions.

图片处理:glide.

代码如下:

                          
                                //
                          
                          
                            okhttp
                          
                          
    implementation "com.squareup.okhttp3:okhttp:4.9.0"
    
                          
                            //
                          
                          
                            gson
                          
                          
    implementation 'com.google.code.gson:gson:2.8.6'
    
                          
                            //
                          
                          
                            fastjson
                          
                          
    implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.83'
    
                          
                            //
                          
                          
                            解决超过65546代码的问题
                          
                          
    implementation 'com.android.support:multidex:1.0.2'
                          
                            
    implementation 
                          
                          "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4"
    
                          
                            //
                          
                          
                            ButterKnife
                          
                          
    implementation 'com.jakewharton:butterknife:10.2.3'
                          
                            
    annotationProcessor 
                          
                          'com.jakewharton:butterknife-compiler:10.2.3'
    
                          
                            //
                          
                          
                             数据库ormlite
                          
                          
    implementation 'com.j256.ormlite:ormlite-android:5.0'
                          
                            
    implementation 
                          
                          'com.j256.ormlite:ormlite-core:5.0'
    
                          
                            //
                          
                          
                            权限请求rxpermissions
                          
                          
    implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'
    
                          
                            //
                          
                          
                            图片处理glide
                          
                          
    implementation 'com.github.bumptech.glide:glide:4.14.2'
                          
                            
    annotationProcessor 
                          
                          'com.github.bumptech.glide:compiler:4.14.2'
                          
                            //
                          
                          
                            运行时 编译时 处理注解
                          
                        

然后在添加一些json和http的utils(写法很多,可以上网任意搜索).

然后创建MyApplication的java文件,代码如下:

                          
                            public
                          
                          
                            class
                          
                           MyApplication 
                          
                            extends
                          
                          
                             Application {
 
    
                          
                          
                            public
                          
                          
                            static
                          
                           Context context;
                          
                            //
                          
                          
                            全局上下文
                          
                          
                            public
                          
                          
                            static
                          
                           List<Activity> activityList = 
                          
                            new
                          
                           ArrayList<Activity>();
                          
                            //
                          
                          
                            用于存放所有启动的Activity的集合
                          
                          
                            public
                          
                          
                            static
                          
                          
                             ApplicationInfo applicationInfo;
​
    @Override
    
                          
                          
                            public
                          
                          
                            void
                          
                          
                             onCreate() {
        SimpleDateFormat df 
                          
                          = 
                          
                            new
                          
                           SimpleDateFormat("yyyy-MM-dd HH:mm:ss"
                          
                            );
        Log.d(
                          
                          "项目启动", "项目启动: " +
                          
                             DateUtils.getTime());
        
                          
                          
                            super
                          
                          
                            .onCreate();
​
        context 
                          
                          =
                          
                             getApplicationContext();
​
        PackageManager packageManager 
                          
                          =
                          
                             getApplicationContext().getPackageManager();
        
                          
                          
                            try
                          
                          
                             {
            packageManager 
                          
                          =
                          
                             getApplicationContext().getPackageManager();
            applicationInfo 
                          
                          = packageManager.getApplicationInfo(getPackageName(), 0
                          
                            );
        } 
                          
                          
                            catch
                          
                          
                             (PackageManager.NameNotFoundException e) {
            applicationInfo 
                          
                          = 
                          
                            null
                          
                          
                            ;
            LogUtils.LogHelperError(
                          
                          "获取applicationInfo报错"
                          
                            , e);
        }
​
        CrashExceptionHandler.getInstance().init(
                          
                          
                            this
                          
                          
                            );
​
        
                          
                          
                            //
                          
                          
                            解决4.x运行崩溃的问题
                          
                          
        MultiDex.install(
                          
                            this
                          
                          
                            );
​
    }
​
    
                          
                          
                            private
                          
                          
                            boolean
                          
                          
                             isDebug() {
        
                          
                          
                            return
                          
                          
                             BuildConfig.DEBUG;
    }
    
                          
                          
                            public
                          
                          
                            static
                          
                          
                             String GetProperties(String propertyName) {
        Properties props 
                          
                          = 
                          
                            new
                          
                          
                             Properties();
        String serviceUrl 
                          
                          = 
                          
                            null
                          
                          
                            ;
        
                          
                          
                            try
                          
                          
                             {
            InputStream in 
                          
                          =context.getAssets().open("appConfig.properties"
                          
                            );
            props.load(in);
            String vaule 
                          
                          =
                          
                             props.getProperty(propertyName);
            serviceUrl 
                          
                          = 
                          
                            new
                          
                           String(vaule.getBytes("ISO-8859-1"), "gbk"
                          
                            );
        } 
                          
                          
                            catch
                          
                          
                             (IOException e) {
            e.printStackTrace();
            AlertDialog.Builder dialog 
                          
                          = 
                          
                            new
                          
                          
                             AlertDialog.Builder(context);
            dialog.setTitle(
                          
                          "错误"
                          
                            );
            dialog.setMessage(
                          
                          "读取配置文件失败"
                          
                            );
            dialog.setCancelable(
                          
                          
                            false
                          
                          
                            );
            removeALLActivity();
        }
        
                          
                          
                            return
                          
                          
                             serviceUrl;
    }
    
                          
                          
                            /**
                          
                          
                            
     * 销毁所有的Activity
     
                          
                          
                            */
                          
                          
                            public
                          
                          
                            static
                          
                          
                            void
                          
                          
                             removeALLActivity() {
        
                          
                          
                            //
                          
                          
                            通过循环,把集合中的所有Activity销毁
                          
                          
                            for
                          
                          
                             (Activity activity : activityList) {
            
                          
                          
                            if
                          
                           (!
                          
                            activity.isFinishing()) {
                activity.finish();
            }
        }
        MyApplication.activityList.clear();
    }
​
}
                          
                        

然后注册CrashException和MultiDex.

然后找到AndroidManifest.xml,注册application,并开启大堆内存,如下:

HTTP请求 。

http请求是我们最常用的工具,下面我们编写一个简单的请求工具.

先创建一个文件夹dto,然后在创建一个base,一个user文件夹.

编写简单的请求和返回实体如下:

然后编写HttpUtils代码如下:

                          
                            public
                          
                          
                            class
                          
                          
                             HttpUtils {
    
                          
                          
                            private
                          
                          
                            static
                          
                          
                            final
                          
                           OkHttpClient client = 
                          
                            new
                          
                          
                             OkHttpClient.Builder()
            .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getX509TrustManager())
            .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
            .connectTimeout(
                          
                          10, TimeUnit.SECONDS)
                          
                            //
                          
                          
                            设置连接超时时间
                          
                          
            .readTimeout(20, TimeUnit.SECONDS)
                          
                            //
                          
                          
                            设置读取超时时间
                          
                          
                                        .build();
​
​
    
                          
                          
                            private
                          
                          
                            static
                          
                          
                            void
                          
                           getRequest(String url, ICallback callback) 
                          
                            throws
                          
                          
                             IOException {
        
                          
                          
                            new
                          
                          
                             Thread() {
            @Override
            
                          
                          
                            public
                          
                          
                            void
                          
                          
                             run() {
                Request request 
                          
                          = 
                          
                            new
                          
                          
                             Request.Builder()
                        .url(url)
                        .build();
​
                
                          
                          
                            try
                          
                           (Response response =
                          
                             client.newCall(request).execute()) {
                    String result 
                          
                          =
                          
                             response.body().string();
                    callback.Call(result);
                } 
                          
                          
                            catch
                          
                          
                             (IOException e) {
                    e.printStackTrace();
                    Log.d(
                          
                          "http异常"
                          
                            , e.getMessage());
                    callback.Call(e.getMessage());
​
                }
            }
        }.start();
​
    }
​
    
                          
                          
                            private
                          
                          
                            static
                          
                          
                            final
                          
                           MediaType mediaType  = MediaType.get("application/json; charset=utf-8"
                          
                            );
​
    
                          
                          
                            private
                          
                          
                            static
                          
                          
                            void
                          
                           postRequest(String url, String param, ICallback callback) 
                          
                            throws
                          
                          
                             IOException {
        
                          
                          
                            new
                          
                          
                             Thread() {
            @Override
            
                          
                          
                            public
                          
                          
                            void
                          
                          
                             run() {
​
                RequestBody body 
                          
                          =
                          
                             RequestBody.create(mediaType, param);
                Request request 
                          
                          = 
                          
                            new
                          
                          
                             Request.Builder()
                        .url(url)
                        .post(body)
                        .build();
​
                
                          
                          
                            try
                          
                           (Response response =
                          
                             client.newCall(request).execute()) {
                    String result 
                          
                          =
                          
                             response.body().string();
                    callback.Call(result);
                } 
                          
                          
                            catch
                          
                          
                             (IOException e) {
                    e.printStackTrace();
                    BaseResult baseResult
                          
                          =
                          
                            new
                          
                          
                             BaseResult();
                    baseResult.code
                          
                          =-1
                          
                            ;
                    callback.Call(JsonUtils.Serialize(baseResult)); 
                }
            }
        }.start(); 
    }
​
    
                          
                          
                            private
                          
                          
                            interface
                          
                          
                             ICallback {
        
                          
                          
                            void
                          
                          
                             Call(String con);
    }
    
                          
                          
                            public
                          
                          
                            interface
                          
                           HttpData<T>
                          
                            {
        
                          
                          
                            public
                          
                          
                            void
                          
                          
                             getData(T result); 
    }
    
                          
                          
                            public
                          
                          
                            static
                          
                           <T> 
                          
                            void
                          
                           post(String param, String urlAddress, HttpData<T>
                          
                             httpData) {
​
        
                          
                          
                            try
                          
                          
                             {
            HttpUtils.postRequest(urlAddress, param, con 
                          
                          ->
                          
                             {
                runOnUiThread(() 
                          
                          ->
                          
                             {
​
                    BaseResult baseResult 
                          
                          = JsonUtils.Deserialize(BaseResult.
                          
                            class
                          
                          
                            , con);
                    
                          
                          
                            if
                          
                           (
                          
                            null
                          
                           != baseResult && baseResult.code == 1
                          
                            ) {
                        Class thisClass 
                          
                          =
                          
                             httpData.getClass();
​
                        Type[] superClassType 
                          
                          =
                          
                             thisClass.getGenericInterfaces();
                        ParameterizedType pt 
                          
                          = (ParameterizedType) superClassType[0
                          
                            ];
​
                        Type[] genTypeArr 
                          
                          =
                          
                             pt.getActualTypeArguments();
                        Type genType 
                          
                          = genTypeArr[0
                          
                            ];
                        Class c1
                          
                          = (Class) genTypeArr[0
                          
                            ];
​
                        T result 
                          
                          =
                          
                             (T)JsonUtils.Deserialize(c1, con);
                        httpData.getData(result);
​
                    } 
                          
                          
                            else
                          
                          
                             {
                        
                          
                          
                            if
                          
                           (
                          
                            null
                          
                           !=
                          
                             baseResult) {
                            ToastUtils.showToast(
                          
                          "数据获取失败:" +
                          
                             baseResult.msg);
                        } 
                          
                          
                            else
                          
                          
                             {
                            ToastUtils.showToast(
                          
                          "数据获取失败"
                          
                            );
                        }
                    } 
                });
            });
        } 
                          
                          
                            catch
                          
                          
                             (IOException e) {
            e.printStackTrace();
        } 
    }
    BaseResult baseResult 
                          
                          = (BaseResult)JsonUtils.Deserialize(BaseResult.
                          
                            class
                          
                          , "con"
                          
                            );
    
                          
                          
                            public
                          
                          
                            static
                          
                           <T> 
                          
                            void
                          
                           get(String param, String urlAddress, HttpData<T>
                          
                             httpData) {
​
        
                          
                          
                            try
                          
                          
                             {
​
            HttpUtils.getRequest(urlAddress, con 
                          
                          ->
                          
                             { 
                runOnUiThread(() 
                          
                          ->
                          
                             { 
                    BaseResult baseResult 
                          
                          = (BaseResult)JsonUtils.Deserialize(Object.
                          
                            class
                          
                          
                            , con);
                    
                          
                          
                            if
                          
                           (
                          
                            null
                          
                           != baseResult && baseResult.code == 1
                          
                            ) {
                        Class thisClass 
                          
                          =
                          
                             httpData.getClass();
​
                        Type[] superClassType 
                          
                          =
                          
                             thisClass.getGenericInterfaces();
                        ParameterizedType pt 
                          
                          = (ParameterizedType) superClassType[0
                          
                            ];
​
                        Type[] genTypeArr 
                          
                          =
                          
                             pt.getActualTypeArguments();
                        Type genType 
                          
                          = genTypeArr[0
                          
                            ];
                        Class c1
                          
                          = (Class) genTypeArr[0
                          
                            ];
​
                        T result 
                          
                          =
                          
                             (T)JsonUtils.Deserialize(c1, con);
                        httpData.getData(result);
​
                    } 
                          
                          
                            else
                          
                          
                             {
                        
                          
                          
                            if
                          
                           (
                          
                            null
                          
                           !=
                          
                             baseResult) {
                            ToastUtils.showToast(
                          
                          "数据获取失败:" +
                          
                             baseResult.msg);
                        } 
                          
                          
                            else
                          
                          
                             {
                            ToastUtils.showToast(
                          
                          "数据获取失败"
                          
                            );
                        }
                    } 
                });
            });
        } 
                          
                          
                            catch
                          
                          
                             (IOException e) {
            e.printStackTrace();
        }
    }
}
                            

这里通过泛型反射直接找到了要序列化的类型,减少了调用时的代码编写,调用代码如下:

                          HttpUtils.get("url","参数", 
                          
                            new
                          
                           HttpHelper.HttpData<LoginCommandResult>
                          
                            () {
     @Override
     
                          
                          
                            public
                          
                          
                            void
                          
                          
                             getData(LoginCommandResult result) {
         
                          
                          
                            int
                          
                           code =
                          
                             result.code;
     }
 });
                          
                        

简单的输入参数和url后,就可以在匿名类的重写函数中获得返回值.

编写Activity与Fragment 。

应用的页面切换是以Fragment的替换为主,以尽量少创建Activity为中心思想,框架实现返回按钮切换fragment.

Activity于Fragment的编写思路如下:

首先编写Base文件,Base文件这里采取二级模式,BaseActivity加KActivity、BaseFragment加KFragment.

KBase文件实现生命周期,Base文件实现通用函数.

KActivity代码简介:

                          
                            /**
                          
                          
                            
     * 
                          
                          
                            @return
                          
                          
                             获取布局的id
     
                          
                          
                            */
                          
                          
                            protected
                          
                          
                            int
                          
                          
                             getLayoutId() {
        
                          
                          
                            return
                          
                           -1
                          
                            ;
    }
    @Override
    
                          
                          
                            protected
                          
                          
                            void
                          
                          
                             onCreate(Bundle savedInstanceState) {
        
                          
                          
                            super
                          
                          
                            .onCreate(savedInstanceState);
        
                          
                          
                            int
                          
                           layoutId =
                          
                             getLayoutId();
        
                          
                          
                            if
                          
                           (layoutId != -1
                          
                            ) {
            
                          
                          
                            this
                          
                          .rootView = View.inflate(
                          
                            this
                          
                          , layoutId, 
                          
                            null
                          
                          
                            );
            setContentView(
                          
                          
                            this
                          
                          
                            .rootView);
        } 
                          
                          
                            else
                          
                          
                             {
            
                          
                          
                            throw
                          
                          
                            new
                          
                           MissingResourceException("未使用getLayoutId()函数初始化view",
                          
                            this
                          
                          .getClass().getName(),"未初始化view"
                          
                            );
        }
        
                          
                          
                            if
                          
                           (savedInstanceState != 
                          
                            null
                          
                          
                            ) { 
           loadActivitySavedData(savedInstanceState);
        } 
    }
                          
                        

Base文件里将设置布局文件给提取出来了,并设置从Bundle里恢复数据的操作.

继承Base文件的Activity实现如下:

                          
                            public
                          
                          
                            class
                          
                           MainActivity 
                          
                            extends
                          
                          
                             BaseActivity {
​
    @Override
    
                          
                          
                            protected
                          
                          
                            int
                          
                          
                             getLayoutId() {
        
                          
                          
                            return
                          
                          
                             R.layout.activity_main;
    }
​
    @Override
    
                          
                          
                            protected
                          
                          
                            void
                          
                          
                             onCreate(Bundle savedInstanceState) {
​
        
                          
                          
                            super
                          
                          
                            .onCreate(savedInstanceState);
​
    }
    
                          
                          
                            /**
                          
                          
                            
     * 菜单、返回键响应
     
                          
                          
                            */
                          
                          
                            
    @Override
    
                          
                          
                            public
                          
                          
                            boolean
                          
                           onKeyDown(
                          
                            int
                          
                          
                             keyCode, KeyEvent event) {
        
                          
                          
                            if
                          
                           (keyCode ==
                          
                             KeyEvent.KEYCODE_BACK) {
            
                          
                          
                            //
                          
                          
                            moveTaskToBack(true);
                          
                          
                                    }
        
                          
                          
                            return
                          
                          
                            true
                          
                          
                            ;
    }
}
                          
                        

继承Base文件的Fragment实现如下:

                          
                            public
                          
                          
                            class
                          
                           MainFragment 
                          
                            extends
                          
                          
                             BaseFragment { 
    @Override
    
                          
                          
                            protected
                          
                          
                            int
                          
                          
                             getLayoutId() {
        
                          
                          
                            return
                          
                          
                             R.layout.fragment_main;
    }
​
    @Override
    
                          
                          
                            protected
                          
                          
                            void
                          
                          
                             onCreate() {
        
    } 
}
                          
                        

可以看到,在类里,使用getLayoutId来指定布局XML文件,这样即可清晰的知道布局文件名,又便于阅读.

PS:Android是支持多个Activity或Fragment使用同一个XML的,但本框架中,拒绝这个特性,要求布局文件与类文件是一对一的关系.

gradle配置 。

app.gradle

打开app的gradle,首先在defaultConfig下增加指定cpu.

                          
                             ndk {
            abiFilters 
                          
                          'armeabi', 'armeabi-v7a', 'x86'
                          
                            
        }
                          
                        

然后在android下面关闭lint检测.

                          
                            //
                          
                          
                            不在googlePlay上线,关闭lint检测
                          
                          
                                lintOptions {
        checkReleaseBuilds 
                          
                          
                            false
                          
                          
                            
        abortOnError 
                          
                          
                            false
                          
                          
                            
    }
                          
                        

project.gradle

我用的新版本AS建的项目,所以默认的代码是这样的.

                          
                            plugins {
    id 
                          
                          'com.android.application' version '7.3.1' apply 
                          
                            false
                          
                          
                            
    id 
                          
                          'com.android.library' version '7.3.1' apply 
                          
                            false
                          
                          
                            
}
                          
                        

这里我们直接将生成的配置删除,粘贴上我们比较熟悉的gradle配置模式,代码如下:

                          
                            buildscript {
    repositories {
        maven { url 
                          
                          'https://jitpack.io'
                          
                             }
        maven { url 
                          
                          "https://oss.jfrog.org/libs-snapshot" }
                          
                            //
                          
                          
                            rxjava
                          
                          
                                    google()
        mavenCentral()
        jcenter() 
                          
                          
                            //
                          
                          
                             Warning: this repository is going to shut down soon
                          
                          
                            ​
    }
    dependencies {
​
        classpath 
                          
                          'com.jakewharton:butterknife-gradle-plugin:10.2.3'
                          
                            
        classpath 
                          
                          'com.android.tools.build:gradle:7.1.2'
                          
                            
​
    }
}
​
allprojects {
    repositories {
        maven { url 
                          
                          'https://jitpack.io'
                          
                             }
        maven { url 
                          
                          "https://oss.jfrog.org/libs-snapshot" }
                          
                            //
                          
                          
                            rxjava
                          
                          
                                    google()
        mavenCentral()
        jcenter() 
                          
                          
                            //
                          
                          
                             Warning: this repository is going to shut down soon
                          
                          
                            ​
    }
}
tasks.withType(JavaCompile) {
    options.encoding 
                          
                          = "UTF-8"
                          
                            
}
task clean(type: Delete) {
    delete rootProject.buildDir
}
                          
                        

要注意的是,新版的settings.gradle也变化了,如果只修改build.gradle编译会抛异常.

生成的setting.gradle代码如下:

                          
                            pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name 
                          
                          = "framework"
                          
                            
include 
                          
                          ':app'
                        

修改代码如下:

                          rootProject.name = "framework"
                          
                            
include 
                          
                          ':app'
                        

首页布局 。

结构搭建好后,我们使用LinkageRecyclerView组件,实现一个简单的双列表布局,界面如下:

结语 。

最后我们看一下项目结构,如下图:

 如上图,一个简单的,有序的,支持activity恢复数据,支持fragment返回的框架就搭建完成了.

---------------------------------------------------------------------------------------------------- 。

到此,手写Android框架一就已经介绍完了.

代码已经传到Github上了,欢迎大家下载.

下篇文章介绍AspectJX实现AOP的几个实用注解.

Github地址: https://github.com/kiba518/AndroidFramework2.0/ 。

---------------------------------------------------------------------------------------------------- 。

注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处! 若您觉得这篇文章还不错,请点击下方的 【 推荐】 ,非常感谢! 。

https://www.cnblogs.com/kiba/p/17262561.html 。

  。

  。

最后此篇关于从头开始,手写android应用框架(一)的文章就讲到这里了,如果你想了解更多关于从头开始,手写android应用框架(一)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com