Android組件化二【跨Module調用方法】

Android組件化二【跨Module調用方法】

經過前一篇的文章,我們已經可以將Module單獨運行了,這一篇的話,我們繼續探索下組件化(其實是模塊化)的內容。
我們這次使用的是AppJoint的組件化方案,仍舊使用上篇文章的代碼來做演示。

Appjoint的詳細說明文檔在 迴歸初心:極簡 Android 組件化方案 — AppJoint

一、目標

這次我們的目標是在app模塊的MainActivity中啓動food模塊的FoodActivity,然後在food模塊的FoodActivity中啓動movie模塊中的MovieActivity。其實但是啓動Activity的話我們可以直接採取Arouter的路由方案來進行,但是這裏的話我們不使用Arouter,而是使用AppJoint提供的方法來演示。

二、準備工作

在food模塊中創建FoodActivity,在movie模塊中創建MovieActivity,app模塊中有默認的MainActivity。創建好必備的Activity後我們就需要準備跨模塊來啓動Activity了。

三、方案

其實當兩個模塊之間想要通訊的話,我們一般需要暴漏出來一個接口,然後給另一個模塊調用,然而這樣的話可能就會發生一個模塊依賴另一個模塊的問題了,所以我們需要將這個接口單獨暴漏出來,這時有兩種方案:

  • 添加一個基礎路由模塊例如叫router,統一聲明所有對外暴漏的接口。所有需要實現或者調用其他模塊的都要依賴該router模塊。
  • 每個需要對外暴漏方法的模塊添加一個專門對外暴漏接口的模塊。例如movie模塊想暴露出來一個方法,那麼添加一個movieApi模塊,該模塊只聲明對外暴漏的接口,movie模塊需要依賴movieApi模塊並實現相應的方法,假如food模塊需要調用該方法,那麼food模塊也需要依賴movieApi模塊。

方案就是這樣,我們按照第二種來進行嘗試:

3.1、新建movieApi模塊

在該模塊中,只創建對外暴漏的接口IMovieRouter,不包含任何業務邏輯,業務只交由movie模塊來實現。該接口包含一個啓動MovieActivity的方法,代碼如下:

package com.cooloongwu.movieapi;

import android.content.Context;

public interface IMovieRouter {
    void startMovieActivity(Context context);
}

3.2、依賴movieApi模塊

3.2.1、movie模塊依賴

movie模塊依賴movieApi模塊後,需要實現IMovieRouter接口,代碼如下:

package com.cooloongwu.movie;

import android.content.Context;

import com.cooloongwu.movieapi.IMovieRouter;

import io.github.prototypez.appjoint.core.ServiceProvider;

@ServiceProvider
public class MovieRouterImpl implements IMovieRouter {
    @Override
    public void startMovieActivity(Context context) {
		Intent intent = new Intent(context, MovieActivity.class);
        context.startActivity(intent);
    }
}

注意: MovieRouterImpl 類需要使用 ServiceProvider 註解!
注意: MovieRouterImpl 類需要使用 ServiceProvider 註解!
注意: MovieRouterImpl 類需要使用 ServiceProvider 註解!

3.2.2、food模塊依賴

food模塊依賴movieApi模塊後,直接可以在FoodActivity中調用IMovieRouter 中的方法了。代碼如下:

        IMovieRouter movieRouter = AppJoint.service(IMovieRouter.class);
        movieRouter.startMovieActivity(this);

3.3、其他流程

因爲app模塊直接依賴了food和movie模塊,所以在app模塊中可以直接啓動food模塊中的FoodActivity了,但是正常開發中不建議在app模塊中做過多的操作,app只作爲一個殼即可。然後在FoodActivity中可以通過AppJoint提供的**AppJoint.service()**來調用其他模塊的方法。

四、單個模塊運行的問題

以上所有步驟當你運行app模塊的時候是沒有問題的,但是當你單獨運行food模塊的時候,此時問題就來了,因爲我們在food模塊中調用了movie模塊中的方法。而單獨food運行的時候,movie模塊是完全不參與的,所以就沒了IMovieRouter 的實現,當我們調用AppJoint.service()就會獲取到null,這時也會產生各種問題。

怎麼解決呢?

還記得我們第一篇文章的殼模塊麼,我們可以在food模塊的殼模塊(比如我們新建可模塊叫runfood模塊)中做些操作,因爲這個模塊在正式打包的時候是不會參與打包的,所以我們可以隨意在其中添加代碼。既然沒有IMovieRouter 的實現,那我們就在可模塊中去實現,當然正常邏輯是走不通的,我們就在實現裏面進行打印或者進行Toast操作吧。

4.1、food模塊中的依賴修改

在原來的food模塊中,可能我們直接依賴movieapi的方法是使用的implementation 。

dependencies {
	...
	implementation project(path: ':movieapi')
}

這樣當runfood模塊依賴food模塊的時候,runfood模塊就會訪問不到movieapi模塊,也就是無法訪問到IMovieRouter 接口,此時我們需要把 implementation修改爲api,這樣將movieapi模塊也暴漏給runfood模塊。

4.2、runfood模塊中實現IMovieRouter

我們給runfood模塊添加IMovieRouter 的Mock類,只打印日誌:

package com.cooloongwu.foodrun;

import android.content.Context;
import android.util.Log;

import com.cooloongwu.movieapi.IMovieRouter;

public class MovieRouterMockImpl implements IMovieRouter {
    @Override
    public void startMovieActivity(Context context) {
        Log.e("MovieRouterMockImpl", "startMovieActivity");
    }
}

4.3、調用IMovieRouter

其實在使用IMovieRouter的等其他暴漏的接口的時候可以直接將這些接口實例存放在類(例如Router類,演示用)中,代碼如下:

package com.cooloongwu.food;

import com.cooloongwu.movieapi.IMovieRouter;

import io.github.prototypez.appjoint.AppJoint;

public class Router {
    public static IMovieRouter movieRouter = AppJoint.service(IMovieRouter.class);
}

使用的時候直接使用 Router.movieRouter.startMovieActivity(this);

這樣的話當然也可以對其進行統一賦值了,也就是我們可以在runfood模塊中添加Application,然後在Application的onCreate()方法中對Router.movieRouter進行賦值,如下:

Router.movieRouter = new MovieRouterMockImpl();

這樣,當我們在單獨運行的時候就不會出現AppJoint.service()獲取的是null的問題了,而是我們Mock的這麼一個實現。

發佈了39 篇原創文章 · 獲贊 46 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章