这是我的情景。
我有一个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活动并没有真正用构造函数实例化。
我已经提出了几种解决方案,但它们在某种程度上都很狡猾:
Icky Solution 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);
}
这很icky因为(a)数据源是静态的,实际上并不与实例相关联,并且(b)消费者可以通过标准活动API而不是静态方法启动活动,这将导致NullPointerException。 / p>
Icky Solution 2
我可以创建一个Provider类,它提供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;
}
}
这似乎有点不那么狡猾,但它仍然有点icky因为活动的依赖性并不明显,并且由于可能有很多路径可以启动它,所以很有可能他们中的一些人会忘记拨打TimeDataSourceProvider.initialize()
。
Icky解决方案3
作为#2的变体,创建一个静态IODependencyProvider
类,必须在app启动时使用所有依赖项进行初始化。
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,因为初始化失败将更难以偷偷摸摸,但它也会在数据类型之间产生相互依赖性,否则这些数据类型就不存在了。
......以及该主题的其他icky变种。
使这些解决方案变得蹩脚的常见主题:
什么是一个不起眼的Android开发人员?
答案 0 :(得分:1)
只要这些依赖项正确实现了Parcelable,您就应该能够将它们添加到您的意图中,然后将它们解压缩为ITimeDataServer并获取正确的类。
答案 1 :(得分:0)
我在最不喜欢的答案中找到了一个很好的解决方案here。
我将库活动定义为抽象,没有默认构造函数,但是接受一个接口的构造函数,如下所示:
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!
}
}
然后,调用代码可以创建一个具体的子类,其中选择的实现 具有无参数构造函数。没有静态成员,轻松自如!
这可以让你抽象并注入各种疯狂的行为! Woooo!
(请注意,具体的子类活动需要手动添加到AndroidManifest.xml,就像所有活动一样,或者应用程序在尝试启动时会崩溃。)