我有一个固定宽度和高度的单元格,让它为100x100px.在那个单元格中,我想要显示一个ImageView
带边框的边框.
我的第一个想法是将背景资源放入ImageView
,并添加1dp的填充以创建边框效果:
<LinearLayout
android:layout_width="100dp"
android:layout_height="100dp" >
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/image_border"
android:padding="1dp"
android:src="@drawable/test_image" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
显然这应该有效,但它没有,或者至少没有预期的那样.
问题是ImageView背景填充整个100x100px单元格的空间,因此,如果图像的宽度小于100px,则顶部和底部边框将显得更大.
注意黄色边框,我需要它在ImageView周围正好1px:
任何帮助,想法,任何建议都非常感谢.
android android-widget android-emulator android-layout android-imageview
在尝试运行测试时,我和Jenkins有一个奇怪的情况.
作业的配置明确指定在这个特定的avd上运行测试:" hudson_en-US_160_HVGA_android-18_armeabi-v7a ",但由于一些奇怪的原因,在构建过程中,找到了2个设备.其中一个设备是前一个设备,但另一个设备称为" unknown-sdk ".
测试在特定的avd上成功执行,并在"unknown-sdk"上失败:
日志的相关部分:
[SR.runTests]在2个设备上执行检测套件.
[SR.runTests] [emulator-8215]开始执行.
[SR.runTests] [localhost:8216]开始执行.在不知名的-sdk-localhost上运行am -w -r -e class com.smoke.tests.LoginTest com.muume.dev.test/android.support.test.runner.AndroidJUnitRunner:8216
2015-06-17 11:54:05 [SDR.printStream] [localhost:8216] STDOUT 11:54:05 I/InstrumentationResultParser:测试运行失败:'无法找到以下内容的检测信息:ComponentInfo {com.muume.dev.测试/ android.support.test.runner.AndroidJUnitRunner}
正如您所看到的,它检测到2个设备:emulator-8215,这是已知的avd,localhost-8216是未知的并导致问题.
我的问题是如何限制测试只运行一个单独的模拟器,以及"unknown-sdk-localhost"来自何处.
编写在 Android 中跨配置更改保持状态的自定义视图是冗长的,看看用于保存一个字段状态的样板代码的数量:
private class SavedState : BaseSavedState {
var amount: Int = 0
constructor(parcel: Parcel) : super(parcel) {
amount = parcel.readInt()
}
constructor (parcelable: Parcelable?) : super(parcelable)
override fun writeToParcel(parcel: Parcel, flags: Int) {
super.writeToParcel(parcel, flags)
parcel.writeInt(amount)
}
companion object CREATOR : Parcelable.Creator<SavedState> {
override fun createFromParcel(parcel: Parcel): SavedState {
return SavedState(parcel)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Android Extensions 插件提供了@Parcelize
可以用来自动生成 的实现的注释Parcelable
,但是在自定义视图的情况下,我们必须BaseSavedState
从Parcelable
.
所以,有这样的东西不会编译:
@Parcelize
data …
Run Code Online (Sandbox Code Playgroud) 我创建了一个从XML布局中膨胀的自定义按钮.一切正常,但不会触发点击监听器.
我怀疑问题是因为android:clickable="true"
属性,因为当我删除它时,触发了点击监听器.但我需要将此属性设置为我的自定义视图使用选择器作为背景,如果我删除它,那么选择器将不再工作.
这是类定义:
public class CustomButton extends LinearLayout{
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_button, this, true);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomButton, 0, 0);
String titleStr = a.getString(R.styleable.CustomButton_title);
String subTitleStr = a.getString(R.styleable.CustomButton_subTitle);
int iconResId = a.getResourceId(R.styleable.CustomButton_icon, R.drawable.ic_launcher);
a.recycle();
TextView title = (TextView)findViewById(R.id.title);
title.setText(titleStr);
TextView subTitle = (TextView)findViewById(R.id.subTitle);
subTitle.setText(subTitleStr);
ImageView icon = (ImageView)findViewById(R.id.icon);
icon.setImageResource(iconResId);
}
}
Run Code Online (Sandbox Code Playgroud)
自定义视图膨胀的XML布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/white_box"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/main_button_selector"
android:clickable="true"
android:gravity="center"
android:orientation="horizontal"> …
Run Code Online (Sandbox Code Playgroud) 现在我们正在使用这样的改造:
service.executeSomeRequest(UserPreferenceRequest userPreferenceRequest, new Callback<UserPreferenceResponse>() {
@Override
public void success(UserPreferenceResponse responseCallback, Response response) {
if (responseCallback.getStatus() == ResponseStatus.OK) {
// Everything is OK, process response
} else {
ApiErrorProcessor.process(responseCallback.getError());
}
}
@Override
public void failure(RetrofitError retrofitError) {
ServerErrorProcessor.process(retrofitError);
}
});
Run Code Online (Sandbox Code Playgroud)
但是我们有很多请求,实际上,我们实现的每个请求都要求我们编写相同的错误代码处理(对于API和服务器错误),这些代码会复制代码.
我们想要的是仅覆盖感兴趣的方法,如果没有提供实现,则执行默认实现.
像这样的东西:
service.executeSomeRequest(UserPreferenceRequest userPreferenceRequest, new
CustomCallback<UserPreferenceResponse>() {
@Override
public void success(UserPreferenceResponse responseCallback, Response response) {
super.success(responseCallback, response);
// Everything is OK, process response
}
});
Run Code Online (Sandbox Code Playgroud)
该CustomCallback
会照顾API和服务器错误的,如果一切正常,然后才将结果传递给调用活动.
在构建RestAdapter
有setRequestInterceptor();
,让我发出之前赶上要求,我想的是类似的东西,比如setResponseInterceptor()
,这将让我将它传递给活动之前赶上响应和治疗有一般性错误,但没有找到相似的东西.
我有一个ListView
在每一行显示从互联网上提取的图像和一个字符串.
一般来说它工作正常.但是我希望控制视图(行)膨胀的方式.默认情况下,当行可见时getView()
,将调用适配器的方法.
这当然不是最好的行为之一,因为如果我有ListView
几百条记录,并且我需要到达底部的那些记录,在滚动时ListView
,getView()
将调用每一行的方法,直到我到达页脚.
所以我想在滚动之后调用getView并且ListView处于暂停/空闲状态,但我不知道如何解决这个问题:
这是我开始的方式:
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState==SCROLL_STATE_IDLE){
// Invoke get view only on visible items
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
});
Run Code Online (Sandbox Code Playgroud)
这是我的适配器的getView:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.row, parent, false);
holder = new ViewHolder();
holder.title = …
Run Code Online (Sandbox Code Playgroud) android android-widget android-emulator android-intent android-layout
我有一个Presenter
使用通过Dagger注入的字段的类,它看起来像这样:
public class RssListPresenter {
@Inject
RssService rssService; // <-- injected field
public RssListPresenter() {
setupDI();
}
private void setupDI() {
DaggerNetworkComponent.builder()
.networkModule(new NetworkModule())
.build()
.inject(this);
}
public void loadItems() {
Rss rss = rssService.getRssFeed()
// ....
}
}
Run Code Online (Sandbox Code Playgroud)
一切正常.现在,我想对RssListPresenter
班级进行单元测试.问题是如何RssService
向演示者提供模拟?
当然,我可以向演示者添加一个新方法setRssService(RssService rssService)
,并使用它来提供单元测试的模拟,但是为单元测试添加这个方法感觉不对.处理这个问题的正确方法是什么?
为了完整性,这里是模块和组件声明:
@Singleton
@Component(modules = NetworkModule.class)
public interface NetworkComponent {
void inject(RssListPresenter presenter);
}
@Module
public class NetworkModule {
@Provides
Retrofit provideRetrofit() {
// ...
}
@Provides
@Singleton
RssService providePcWorldRssService(Retrofit retrofit) …
Run Code Online (Sandbox Code Playgroud) 正如Dagger文档中所建议的那样,对于单元测试,我们根本不需要涉及Dagger,并且对于提供的示例,它是有意义的:
class ThingDoer {
private final ThingGetter getter;
private final ThingPutter putter;
@Inject ThingDoer(ThingGetter getter, ThingPutter putter) {
this.getter = getter;
this.putter = putter;
}
String doTheThing(int howManyTimes) { /* … */ }
}
Run Code Online (Sandbox Code Playgroud)
使用这个类结构,单元测试很简单,只需模拟getter
和putter
,将它们作为构造函数参数传递,指示mockito在与任何这些对象交互时返回什么,然后进行断言doTheThing(...)
.
我在测试中苦苦挣扎的地方是我必须对类似于以下结构的类进行单元测试:
class ThingDoer {
@Inject
ThingGetter getter;
@Inject
ThingPutter putter;
@Inject
ThingMaker maker;
@Inject
// other 10 objects
public ThingDoer() {
App.getThingComponent().inject(this);
}
String doTheThing(int howManyTimes) { /* … */ }
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我不再使用构造函数注入,而是使用字段注入.主要原因是构造函数中没有太多参数.
有没有办法在ThingDoer
使用字段注入提供所有依赖项时注入模拟依赖项?
我已按照KMM 实践教程了解如何使用 KMM 构建示例应用程序,并且能够成功完成所有步骤!(Yu-huu!)现在我正在尝试在生产应用程序中做一个小型的 POC。所以我创建了一个新的KMM共享模块并将其添加到Android项目中。对于 Android 部分,它工作正常,但我不知道如何将共享模块包含到 iOS 应用程序中。
根据此链接,文件中应引用iOS项目目录gradle.properties
:
xcodeproj=~/iOSProjects/TestKMM
Run Code Online (Sandbox Code Playgroud)
但是当我尝试导入共享模块时,xcode 抱怨没有这样的模块:
所以我认为仅仅引用 中的 iOS 项目gradle.properties
是不够的。我一定还缺少其他东西。
另外,我检查了build
共享模块的目录,据我所知,没有生成 iOS 工件。(这与存在 a 的实践教程项目不同bin/iosX64/debugFragmework/shared.framework/ ....
。)
android ios kotlin-multiplatform kotlin-multiplatform-mobile
对于我正在使用的应用程序,我需要集成Google Cloud Messaging。在玩了一些不同的示例之后,我能够在设备上发送和接收通知。
但是,我遇到了一个有趣的情况。据我所知(如果我错了,请纠正我),每个设备和每个应用程序都会发出registration_id。
我正在使用的应用程序支持登录功能。安装该应用程序后,用户首次登录(将其命名为“ UserA”),我从GCM请求registration_id,然后将其发送到我的服务器。
现在,假设UserA已注销,并将其设备交给某个UserB进行登录。换句话说,UserB使用UserA的设备登录。
问题在于,如果同时UserA收到通知,则UserB将能够拦截该通知。而且,如果UserB收到通知,他将无法接收该通知。
这似乎很正常,因为registration_id是针对每个设备和每个应用程序的,但是对于我而言,这似乎并不合理。
所以我想问是否有办法使registration_id依赖于某些用户ID(除了设备和应用程序之外)?或者,如何使登录用户仅接收自己的通知?
android ×10
unit-testing ×2
dagger-2 ×1
ios ×1
java ×1
jenkins ×1
kotlin ×1
kotlin-multiplatform-mobile ×1
mockito ×1
parcelable ×1
retrofit ×1
spoon ×1