![](/img/trans.png)
[英]How do I ship an Android Library (aar) with remote dependencies (gradle)?
[英]How do I abstract away dependencies in Android library code?
这是我的情况。
我有一个Android活动,我想在其中抽象我的I / O依赖项。 依赖关系由以下接口表示(为简洁起见而编辑):
public interface ITimeDataServer {
TimeRecord[] get(int userID);
void save(TimeRecord record);
}
我想要的是使我的活动能够调用这些接口方法,并使实现由调用代码提供。 (我认为是相当标准的)。
ITimeDataServer myServer;
int myUserID;
void loadRecords() {
TimeRecord[] records = myServer.get(myUserID);
// etc...
}
我的困难是,如何确保设置myServer
?
这似乎是一个常见问题,但我找不到干净的解决方案。
我首先想到的是myServer
将通过构造函数传递,但Android活动实际上并未使用构造函数实例化。
我已经提出了几种解决方案,但是它们在某些方面都很棘手:
棘手的解决方案1
创建一个静态方法以启动带有ITimeDataServer参数的活动类,并将其存储在活动可以从中访问它的静态变量中:
private static ITimeDataSource theDataSource;
public static void launch(Activity currentActivity, ITimeDataSource dataSource) {
theDataSource = dataSource;
Intent intent = new Intent(currentActivity, MainActivity.class);
currentActivity.startActivity(intent);
}
这很棘手,因为(a)数据源是静态的且实际上未与实例关联,并且(b)使用者可以通过标准活动API而不是此静态方法来启动活动,这将导致NullPointerException。
棘手的解决方案2
我可以创建一个提供者类,该类提供ITimeDataSource的单例实例,使用前需要由调用库初始化该实例:
public class TimeDataSourceProvider {
private static ITimeDataSource myDataSource = null;
public void initialize(ITimeDataSource dataSource) {
myDataSource = dataSource;
}
public ITimeDataSource get() {
if (myDataSource == null)
throw new NullPointerException("TimeDataSourceProvider.initialize() must be called before .get() can be used.");
else
return myDataSource;
}
}
这似乎不那么棘手,但仍然有点棘手,因为该活动的依赖性并不明显,并且由于可能有许多启动它的路径,因此其中一些人很可能会忘记调用TimeDataSourceProvider.initialize()
。
棘手的解决方案3
作为#2的变体,创建一个静态IODependencyProvider
类,必须在应用程序启动时使用所有依赖项对其进行初始化。
public class IODependencyProvider {
static ITimeDataSource myTimeData;
static IScheduleDataSource myScheduleData; // etc
public static void initialize(ITimeDataSource timeData, IScheduleDataSource scheduleData /* etc */) {
myTimeData = timeData;
myScheduleData = scheduleData;
//etc
}
public static ITimeDataSource getTimeData() {
if (myTimeData == null)
throw new NullPointerException("IODependencyProvider.initialize() must be called before the getX() methods can be used.");
else
return myTimeData;
}
// getScheduleData(), etc
}
这似乎比#1和#2更好,因为初始化失败会更容易被偷偷摸摸,但是它还会在原本不需要的数据类型之间建立相互依赖性。
...以及该主题的其他引人注目的变化。
使这些解决方案崩溃的常见主题:
Nooby Android开发人员该做什么?
只要这些依赖关系正确实现了Parcelable,您就应该能够将它们添加到您的意图中,然后将它们作为ITimeDataServer取消打包并获取正确的类。
我发现了一个很好的解决方案在这里 ,在最喜爱的答案。
我将库活动定义为抽象的,没有默认的构造函数,但是带有接口的构造函数,如下所示:
public abstract class TimeActivity extends AppCompatActivity {
private ITimeDataSource myTimeDataSource;
public TimeActivity(@NonNull ITimeDataSource dataSource) {
myTimeDataSource = dataSource;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time);
// do stuff with myTimeDataSource!
}
}
然后,调用代码可以使用其选择的实现创建一个具体的子类,该实现确实具有无参数的构造函数。 没有静态成员,轻松自如!
这使您可以抽象并注入各种疯狂的行为! !
(请注意,具体的子类活动需要像所有活动一样手动添加到AndroidManifest.xml中,否则该应用在尝试启动时会崩溃。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.