我的EditorFactory在Google Play测试中崩溃。这个类被嵌入到我编写的渲染器中,用来扩展Xamarin Forms Editor控件。
Error:
FATAL EXCEPTION: Thread-3
Process: com.MyApp.MyApp, PID: 23307
android.runtime.JavaProxyThrowable: System.InvalidCastException: Specified cast is not valid.
at MyApp.EditorExRenderer+NoCopyEditableFactory.NewEditable (Java.Lang.ICharSequence source) [0x00000] in <0c33163fb4704d40bbc13286b4698089>:0
at Android.Text.EditableFactory.n_NewEditable_Ljava_lang_CharSequence_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_source) [0x0000f] in <0ce592b1e5104b27bf696797bee3407f>:0
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_L (_JniMarshal_PPL_L callback, System.IntPtr jnienv, System.IntPtr klazz, System.IntPtr p0) [0x00005] in <0ce592b1e5104b27bf696797bee3407f>:0
at crc645beb7f91af2d2a49.EditorExRenderer_NoCopyEditableFactory.n_newEditable(Native Method)
at crc645beb7f91af2d2a49.EditorExRenderer_NoCopyEditableFactory.newEditable(EditorExRenderer_NoCopyEditableFactory.java:29)
at android.widget.TextView.setText(TextView.java:6219)
at android.widget.TextView.setText(TextView.java:6156)
at android.widget.EditText.setText(EditText.java:121)
at android.widget.TextView.setText(TextView.java:6108)
at androidx.test.espresso.action.ReplaceTextAction.perform(ReplaceTextAction.java:1)
at androidx.test.tools.crawler.platform.hybrid.HybridInteractionController$1.perform(HybridInteractionController.java:2)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:2)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:21)
at androidx.test.espresso.ViewInteraction.-$$Nest$mdoPerform(Unknown Source:0)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:6)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:1)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7664)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
下面是我的渲染器代码的骨架。我希望这足以让您大致了解我是如何使用工厂的:
public class EditorExRenderer : EditorEx
{
public EditorExRenderer(Android.Content.Context context) : base(context)
{
}
private class NoCopyEditableFactory : EditableFactory // Editable.Factory in Java
{
public override IEditable NewEditable(ICharSequence source) => (IEditable)source;
}
void Load(string displayString)
{
...
...
SetSpannable(displayString);
...
...
}
void SetSpannable(string text)
{
_spannable = new SpannableStringBuilder(text);
//set span
Span span = new Span();
...
...
_spannable.SetSpan(span, start, end, SpanTypes.InclusiveInclusive);
...
...
Control.SetText(_spannable, TextView.BufferType.Spannable);
}
private void Control_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
...
...
SetSpannable(newText);
}
}
知道为什么它会崩溃吗?
ICharSequence
和IEditable
是两种不同的接口。所以我们不能在它们之间进行类型强制转换。
此外,您可以尝试创建EditableFactory的实例并在某处使用它。如:
var NoCopyEditableFactory = new EditableFactory();
Control.SetEditableFactory(NoCopyEditableFactory);
我复制了NoCopyEditableFactory盲目地从另一个StackOverflow帖子,所以我删除了它,一切都很好:
public class EditorExRenderer : EditorEx
{
public EditorExRenderer(Android.Content.Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Control != null)
{
...
...
//****************
//create new SpannableFactory, rather than NoCopyEditableFactory
Control.SetSpannableFactory(new SpannableFactory());
...
...
}
}
//private class NoCopyEditableFactory : EditableFactory // Editable.Factory in Java
//{
//public override IEditable NewEditable(ICharSequence source) => (IEditable)source;
//}
void Load(string displayString)
{
...
...
SetSpannable(displayString);
...
...
}
void SetSpannable(string text)
{
_spannable = new SpannableStringBuilder(text);
//set span
ForegroundColorSpanEx span = new Span();
...
...
_spannable.SetSpan(span, start, end, SpanTypes.InclusiveInclusive);
...
...
Control.SetText(_spannable, TextView.BufferType.Spannable);
}
private void Control_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
...
...
SetSpannable(newText);
}
}
我发现我的新代码正在产生错误。使用前面的NoCopyEditableFactorySpanChange方法可以动态更改文本字体的颜色。在我的新代码上面,动态着色不起作用。我尝试使用默认的EditableFactory,而不是NoCopyEditableFactory,这也不会动态地为文本上色。
所以我又回到原点了。什么好主意吗?
void SpanChange(int index)
{
Span span;
int start, end;
span = _spans[index];
start = _spannable.GetSpanStart(span);
end = _spannable.GetSpanEnd(span);
span.SetColor(cb.Color);
_spannable.SetSpan(span, start, end, SpanTypes.InclusiveInclusive);
Invalidate();
}
public class ForegroundColorSpanEx : ForegroundColorSpan
{
private Color Color;
public ForegroundColorSpanEx(Color c)
: base(c)
{
Color = c;
}
public override void UpdateDrawState(TextPaint textPaint)
{
base.UpdateDrawState(textPaint);
textPaint.Color = Color;
}
public void SetColor(Color c)
{
Color = c;
}
}