[s1e6]超详细!3小时从0开始开发一个GitHub客户端(Android)

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情

作者:国民程序员
项目视频:https://www.bilibili.com/video/BV1vz4y1C7cC/
项目资料:微信搜索 【国民程序员】,回复 “github”
转载请保留此引用,感谢!

导语:

最近收到本书《Android App开发入门与实战》的一些读者的反馈,希望书籍最后章节的GitHub客户端实战开发环节能否单独拿出来讲解一遍,最好能通过视频形式展示出来。于是这段时间把GitHub客户端开发教程重新整理了一遍,并录制成视频。

这是第6篇,本篇正式进入编码阶段,首先介绍架构和模块的搭建。

本章节建议观看视频讲解。

微信搜索 【国民程序员】,回复 “github”,即可获取本项目源码和后续完整的实战文章教程。

一、架构

1. MVVM

在这里插入图片描述
BaseViewModel是业务VM的基类;

public abstract class BaseViewModel<T extends BaseRepository> extends AndroidViewModel {

    protected Context context;

    protected T repository;

    public BaseViewModel(@NonNull Application application) {
        super(application);
        context = application;
        repository = TUtil.getInstance(this, 0);
    }

}

BaseRepository是业务Model的基类;

public abstract class BaseRepository {

    private final String TAG = "BaseRepository";

    protected MutableLiveData<Data<GithubAuth>> liveDataLogin;

    public void login(String authorization) {
        ... ...
    }
}

(附)AppRepository处理跟数据相关的业务入口;
在这里插入图片描述

二、模块

1. 网络

public enum RetrofitManager {
    INSTANCE;

    private final String TAG = "RetrofitManager";

    private HashMap<String, Retrofit> retrofitMap = new HashMap<>();

    private void createRetrofit(@NonNull String baseUrl, boolean isJson) {
        int timeOut = Constant.HTTP_TIME_OUT;
        Cache cache = new Cache(FileUtil.getHttpImageCacheDir(MyApplication.getInstance()),
                Constant.HTTP_MAX_CACHE_SIZE);

        // Log信息拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);//这里可以选择拦截级别

        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder()
                .connectTimeout(timeOut, TimeUnit.MILLISECONDS)
                .addInterceptor(loggingInterceptor)
                .cache(cache);
        if (!StringUtil.isEmpty(App.sAuthorization)) {
            okHttpClientBuilder.interceptors().add(0, chain -> {
                Request.Builder reqBuilder = chain.request()
                        .newBuilder().addHeader("Authorization", App.sLastLoginUser.getToken());
                return chain.proceed(reqBuilder.build());
            });
        }

        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())//定义转化器,用Gson将服务器返回的Json格式解析成实体
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//关联RxJava
                .client(okHttpClientBuilder.build());

        if (isJson) {
            builder.addConverterFactory(GsonConverterFactory.create());
        } else {
            builder.addConverterFactory(SimpleXmlConverterFactory.createNonStrict());
        }

        retrofitMap.put(baseUrl + "-" + isJson, builder.build());
    }

    /**
     * 区分登录态的Retrofit
     *
     * @param baseUrl
     * @param withLogin
     * @return
     */
    public Retrofit getRetrofit(@NonNull String baseUrl, boolean withLogin) {
        String key = baseUrl + "-" + withLogin;
        if (!retrofitMap.containsKey(key)) {
            createRetrofit(baseUrl, withLogin);
        }
        return retrofitMap.get(key);
    }

    public Retrofit getRetrofit(@NonNull String baseUrl) {
        return getRetrofit(baseUrl, true);
    }
}

2. 图片

QuickModule:自动切换功能模块的实现方式,以图片模块为例。

QuickModule.imageProcessor().loadNet(url, mImageView);

public class QuickModule {

    private static IImageProcessor mIImageProcessor;
    private static ImageConfig mImageConfig;

    //配置生效
    public static void launch() {
        //image
        if (mIImageProcessor == null) {
            mIImageProcessor = new GlideProcessor();
        }
        mIImageProcessor.init(MyApplication.getInstance(), mImageConfig);
    }

    //image调用入口
    public static <T extends IImageProcessor> T imageProcessor() {
        if (mIImageProcessor != null) {
            return (T) mIImageProcessor;
        }
        return (T) new GlideProcessor();
    }

    //image配置入口
    public static ImageConfig configImage() {
        return configImage(null);
    }

    //image配置入口
    public static ImageConfig configImage(IImageProcessor processor) {
        if (processor == null) {
            mImageConfig = new ImageConfig();
        }
        else {
            mIImageProcessor = processor;
            mImageConfig = new ImageConfig();
        }
        return mImageConfig;
    }
}

3. 数据库

在这里插入图片描述
Room主要由三部分组成:Database、Entity、Dao。
在这里插入图片描述

4. base

在这里插入图片描述

public abstract class BaseActivity extends QuickActivity {


    //默认不使用自带titlebar
    @Override
    protected boolean isLoadDefaultTitleBar() {
        return false;
    }

    @Override
    protected void getBundleExtras(Bundle extras) {

    }

    //默认不开启eventbus
    @Override
    protected boolean isBindEventBus() {
        return false;
    }

    @Override
    protected void onEventComing(EventCenter eventCenter) {

    }

    @Override
    protected Intent getGoIntent(Class<?> clazz) {
        if (BaseFragment.class.isAssignableFrom(clazz)) {
            Intent intent = new Intent(this, FragmentActivity.class);
            intent.putExtra("fragmentName", clazz.getName());
            return intent;
        } else {
            return super.getGoIntent(clazz);
        }
    }
}
public abstract class MVVMActivity<T extends BaseViewModel> extends BaseActivity {

    protected T mViewModel;

    public T getViewModel() {
        return mViewModel;
    }

    public Class<T> getTClass() {
        try {
            return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void initViewsAndEvents(Bundle savedInstanceState) {
        if (mViewModel == null) {
            Class<T> clazz = getTClass();
            if (clazz != null) {
                mViewModel = ViewModelProviders.of(this).get(getTClass());
            }
        }
    }
}

5. 数据

状态 + 泛型 + msg

public class Data<T> {

    @Status
    public int status;

    @Nullable
    public T data;

    @Nullable
    public String msg;

    public Data(@Status int status, @Nullable T data, String msg) {
        this.status = status;
        this.data = data;
        this.msg = msg;
    }

    public static <T> Data<T> loading() {
        return new Data<>(Status.LOADING, null, null);
    }

    public static <T> Data<T> success(@Nullable T data) {
        return new Data<>(Status.SUCCESS, data, null);
    }

    public static <T> Data<T> error(String msg) {
        return new Data<>(Status.ERROR, null, msg);
    }

    public boolean showLoading() {
        return status == Status.LOADING;
    }

    public boolean showSuccess() {
        return status == Status.SUCCESS;
    }

    public boolean showError() {
        return status == Status.ERROR;
    }
}

6. 其它

  1. RxPermissions
	RxPermissions rxPermissions = new RxPermissions(this);  
	        rxPermissions  
	                .request(Manifest.permission.CAMERA)  
	                .subscribe(granted -> {  
	                    if (granted) {
	                        ToastUtil.showToast("授权成功!");  
	                    } else {  
	                        ToastUtil.showToast("授权失败!");  
	                    }  
	                });  
  1. ButterKnife
	private Unbinder mUnbinder;  
	  
	@Override  
	    protected void onCreate(Bundle savedInstanceState) {  
	        super.onCreate(savedInstanceState);  
	        ......  
	        mUnbinder = ButterKnife.bind(this);  
	        ......  
	}  
	  
	@Override  
	    protected void onDestroy() {  
	        super.onDestroy();  
	        if (mUnbinder != null) {  
	            mUnbinder.unbind();  
	        }  
	         ......
	} 
  1. EventBus
	@Override  
	    protected void onCreate(Bundle savedInstanceState) {  
	        super.onCreate(savedInstanceState);  
	    	   ......  
	         if (isBindEventBus()) {  
	            EventBus.getDefault().register(this);  
	        }  
	}  
	  
	@Override  
	    protected void onDestroy() {  
	        super.onDestroy();  
	        if (isBindEventBus()) {  
	            EventBus.getDefault().unregister(this);  
	        }  
	         ......
	}  

感兴趣的朋友可以查看下一篇博客:[s1e7]超详细!3小时从0开始开发一个GitHub客户端

想要获取本实战项目后续完整文章教程和视频内容,请在微信搜索 【国民程序员】,回复 “github”即可。

欢迎关注我的技术公众号:国民程序员,我们的目标:输出干货

  1. 每天分享原创技术文章
  2. 海量免费技术资料和视频学习资源
  3. 分享赚钱门道,带领程序员走向财务自由
图片名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值