ブロガーの声明:
追加のリンクおよび著者情報の最初にこの記事を転載し、予約済みとしてマークしてください。ブロガーによるこの記事 ひげニャー サポートやアドバイスの元の聴衆。
この記事では、最初にこのに登場 ブロガー:ひげニャー | ブログのホームページ:https://blog.csdn.net/smile_running
MVPアーキテクチャシリーズ:
AndroidのMVPアーキテクチャ(a)のMVPアーキテクチャは、実際の使用で導入します
AndroidのMVPアーキテクチャ(2)基本的なフレームワークの設計のBaseMVP MVP
動的プロキシとメモリリーク分析アンドロイドMVP MVPアーキテクチャ(3つ)
AndroidのMVPアーキテクチャ(4)MVPの一般的な構成モデル
AndroidのMVPアーキテクチャ(e)のMVP依存性注入プレゼンターの複数
MVPパッケージのAndroidのMVPアーキテクチャ(6)をBaseFragment
AndroidのMVPアーキテクチャプロキシモードの(7)MVPコードの重複排除する(終了)
送信元アドレス:
githubのダウンロード:MVPDemo
CSDNダウンロード:MVPDemo
最初からMVPアーキテクチャの概要を説明する記事のMVPアーキテクチャシリーズの数日間シーケンシャル書き込みは、今BaseMVPフレームワークは基本的に完了し、カプセル化された、このプロセスは、私にとっては、ほとんどの週に関係なくかかりました知識やコードを書く能力が、大幅に改善されています。ブログは、実際には、再び自分の学校をまとめるために、学習過程で、私はほとんどの人が私のようであることを信じて、コードが終了し、また、基本的なニーズを取得し、その後、コードはさておきスローされますされ、私はその時を感じるだろう、しかし、次回に問題が発生したまで、問題を解決する方法を見つけていないし、何のアイデア。
もちろん、他の一方で、知識の欠如で見つけることができるブログを書きます。例えば、BaseMVPフレームワークのこの段階を書いて、私たちは直接リコール自分のブログを開いて、また、ほとんどの知識を反映したものである使用私は、反射する前に記事を書きました。いわゆる:古いの確認、教師としての役割を果たすことができます。
だから、この記事では、これは、読んで、読んで短編小説の速いフォーム、および終わり近くに行う7期連続の記事が公開され、最終的な要約と整流を作るために私たちのBaseMVPフレームワークを提供することです、それはしませんでした良いものは書くためにどのような。それは密接に関連して、いくつかあり、読書に推定されている比較的小さい、私たちは私の生徒たちにここで長いったらしいかかる場合があり、すべての多忙な解決の実用的な問題は、今より多くの余暇を合計しているが、共有する人々の視点に立って、私はそれが助けをもたらすことができ、私の記事は誰かを見ていきたいと考えています。
あなたは、私は全くのナンセンスを見たときに、問題とコードで直接見て好きではない見たい場合には思考を開き、寝具など少し要約を書き、私は、これを行うことを好みます。我々は(パートのベースパッケージのAndroid MVPアーキテクチャ(6)BaseFragmentのMVPは)BaseFragment基本クラスをカプセル化しますが、彼らはパートの最後に、コードの冗長性の場合に登場し、この時間は、私はこの後、この質問を投げます我々は、このコード、コードの重複部の最初の外観を解決する方法を正確に繰り返します。
BaseActivity基本クラスコード:
public abstract class BaseActivity extends AppCompatActivity implements IBaseView {
/**
* 保存使用注解的 Presenter ,用于解绑
*/
private List<BasePresenter> mInjectPresenters;
protected abstract void initLayout(@Nullable Bundle savedInstanceState);
protected abstract void initViews();
protected abstract void initData();
@SuppressWarnings("SameParameterValue")
protected <T extends View> T $(@IdRes int viewId) {
return findViewById(viewId);
}
@SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initLayout(savedInstanceState);
mInjectPresenters = new ArrayList<>();
//获得已经申明的变量,包括私有的
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
//获取变量上面的注解类型
InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
if (injectPresenter != null) {
try {
Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
BasePresenter mInjectPresenter = type.newInstance();
mInjectPresenter.attach(this);
field.setAccessible(true);
field.set(this, mInjectPresenter);
mInjectPresenters.add(mInjectPresenter);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}catch (ClassCastException e){
e.printStackTrace();
throw new RuntimeException("SubClass must extends Class:BasePresenter");
}
}
}
initViews();
initData();
}
@Override
protected void onDestroy() {
super.onDestroy();
/**
* 解绑,避免内存泄漏
*/
for (BasePresenter presenter : mInjectPresenters) {
presenter.detach();
}
mInjectPresenters.clear();
mInjectPresenters = null;
}
@Override
public Context getContext() {
return this;
}
}
BaseFragment基本クラスコード:
public abstract class BaseFragment extends Fragment implements IBaseView {
private List<BasePresenter> mInjectPresenters;
private View mLayoutView;
protected abstract @LayoutRes int setLayout();
protected abstract void initViews(@Nullable Bundle savedInstanceState);
protected abstract void initData();
@SuppressWarnings("ConstantConditions")
protected <T extends View> T $(@IdRes int viewId) {
return this.getView().findViewById(viewId);
}
@SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(setLayout(), container, false);
mInjectPresenters = new ArrayList<>();
//获得已经申明的变量,包括私有的
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
//获取变量上面的注解类型
InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
if (injectPresenter != null) {
try {
Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
BasePresenter mInjectPresenter = type.newInstance();
//绑定
mInjectPresenter.attach(this);
field.setAccessible(true);
field.set(this, mInjectPresenter);
mInjectPresenters.add(mInjectPresenter);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (java.lang.InstantiationException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
throw new RuntimeException("SubClass must extends Class:BasePresenter");
}
}
}
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews(savedInstanceState);
initData();
}
@Override
public void onDestroy() {
super.onDestroy();
for (BasePresenter presenter : mInjectPresenters) {
presenter.detach();
}
mInjectPresenters.clear();
mInjectPresenters = null;
}
}
それはフレームワークとして懸念されているので、我々はこの問題を解決するためのコードを繰り返す必要があります。私たちが克服しなければならない問題であるフレームワーク、彼らは繰り返しのコードの問題を解決するために多くの方法を参照してくださいどのように他の誰かによって書かれた比較フレームワークを書き込むには、これらの方法から学ぶ、私たちのコードの導入、この変更私たち自身のものと。次のように比較コードBaseActivityとBaseFragment重複コードが見つかりました:
1で2回:
2で繰り返します。
リピートコードのためにそれが行くように、親クラスを抽出した後、二つのサブカテゴリーは、それを継承しているようにすることです、これはコードの再利用を行うことができます私たちの最も基本的なアプローチです。しかし、ここで親クラスを抽出する方法です、私たちの問題で使用することは適切ではありませんJavaは特性の単一継承であるため。
私たちのBaseActivityを開始するために活動を継承しなければならないが、それはBaseFragmentフラグメントを継承しなければなりませんので。だから、そこには、継承と係合することができない、いじりすることはできませんあなたが複数のインタフェースを持つことができるので、あなただけの、しようとするインターフェースのメソッドを使用することができます。したいと思ったので、これはそれを行うと、最終的には使用プロキシモードは、このケースを処理するための良い数を、見つける必要があり、プロキシメソッドは、プロキシモードのインターフェイスは、次のコードを提供しなければなりません。
エージェントインターフェース:IProxyインタフェース
package com.test.mvp.mvpdemo.mvp.v7.proxy;
public interface IProxy {
void bindPresenter();
void unbindPresenter();
}
エージェントインターフェース、次のようにプレゼンター、上記繰り返される特定の部分を結んだ和解に私たちをバインドする抽象メソッドを提供し、我々は統一されたエージェント反復コードのクラス・インターフェースを作成する必要があり、コードは次のとおりです。
IProxyインターフェースクラス:ProxyImplクラス
package com.test.mvp.mvpdemo.mvp.v7.proxy;
import com.test.mvp.mvpdemo.mvp.v7.basemvp.BasePresenter;
import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;
import com.test.mvp.mvpdemo.mvp.v7.inject.InjectPresenter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class ProxyImpl implements IProxy {
private IBaseView mView;
private List<BasePresenter> mInjectPresenters;
public ProxyImpl(IBaseView view) {
this.mView = view;
mInjectPresenters = new ArrayList<>();
}
@SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
@Override
public void bindPresenter() {
//获得已经申明的变量,包括私有的
Field[] fields = mView.getClass().getDeclaredFields();
for (Field field : fields) {
//获取变量上面的注解类型
InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
if (injectPresenter != null) {
try {
Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
BasePresenter mInjectPresenter = type.newInstance();
mInjectPresenter.attach(mView);
field.setAccessible(true);
field.set(mView, mInjectPresenter);
mInjectPresenters.add(mInjectPresenter);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
throw new RuntimeException("SubClass must extends Class:BasePresenter");
}
}
}
}
@Override
public void unbindPresenter() {
/**
* 解绑,避免内存泄漏
*/
for (BasePresenter presenter : mInjectPresenters) {
presenter.detach();
}
mInjectPresenters.clear();
mInjectPresenters = null;
}
}
重複したコードは、すべてに描かれた ProxyImplのに対処するためのクラスなので、私たちはBaseActivityとBaseFragmentで重複したコードを記述する必要はありませんが、この場合には、二つの薬剤は、新しい実装クラスを作成する必要があり、クラスがProxyActivityあり、特別なエージェントに関連付けられたコードの活性は、次のようにコードは、具体的フラグメントプロキシコードに関連した別のクラスProxyFragmentあります。
新建 ProxyActivity 类:
package com.test.mvp.mvpdemo.mvp.v7.proxy;
import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;
public class ProxyActivity<V extends IBaseView> extends ProxyImpl {
public ProxyActivity(V view) {
super(view);
}
}
新建 ProxyFragment 类:
package com.test.mvp.mvpdemo.mvp.v7.proxy;
import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;
public class ProxyFragment<V extends IBaseView> extends ProxyImpl {
public ProxyFragment(V view) {
super(view);
}
}
这里两个代理类暂时没上面代码,因为还没上面业务逻辑要处理。不过,必须要传入一个泛型的 IBaseView 对象,这里的原因就是我们的 ProxyImpl 类中的 presenter 调用 attach() 方法去绑定 View 时,这个 View 是继承 IBaseView 的,所以这必须要一个参数给它,通过继承 ProxyImpl 类将这个 view 用构造函数的方式传给父类。
到这里,就好了。总得来说,这里就新建了几个代理类,我们来看一下项目包发生的变化吧:
好了,你一定期待我们的 BaseActivity 和 BaseFragment 中的代码到底少了多少,或者你肯定想知道如何调用代理类,下面来看看吧:
修改 BaseActivity 基类:
public abstract class BaseActivity extends AppCompatActivity implements IBaseView {
private ProxyActivity mProxyActivity;
protected abstract void initLayout(@Nullable Bundle savedInstanceState);
protected abstract void initViews();
protected abstract void initData();
@SuppressWarnings("SameParameterValue")
protected <T extends View> T $(@IdRes int viewId) {
return findViewById(viewId);
}
@SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initLayout(savedInstanceState);
mProxyActivity = createProxyActivity();
mProxyActivity.bindPresenter();
initViews();
initData();
}
@SuppressWarnings("unchecked")
private ProxyActivity createProxyActivity() {
if (mProxyActivity == null) {
return new ProxyActivity(this);
}
return mProxyActivity;
}
@Override
protected void onDestroy() {
super.onDestroy();
mProxyActivity.unbindPresenter();
}
@Override
public Context getContext() {
return this;
}
}
调用很简单,首先实例化 ProxyActivity 对象,然后调用它父类的 bind 和 unbind 方法就可以了。很明显,把那一坨长长的代码抽掉了以后,BaseActivity 显得异常清爽,瞬间瘦身成功。这里我就不对 BaseFragment 进行说明了,代码步骤都一样。
做一下最后的总结,这里运用了一个设计模式:代理模式,不懂的可以去查一查。这篇文章的结束,也代表这本系列文章的结束,因为我们 BaseMVP 框架已经可以上手使用了,我们从第一篇的 MVP 的使用到这篇的 BaseMVP 封装过程中发现的一些问题和解决方法都差不多仔仔细细的写清楚,写明白了。当然,最重要的不是代码,而是解决问题的思路和方法。
如果你有足够的学习热情,你可以从第一篇到最后一篇依次看下来,我相信你收获的一定不少。对了,这里肯定有人需要源代码,我会发到 csdn 和 github 上,喜欢的可以点个赞,如果有错的,欢迎纠错。