Android Volley获取JSON后ListView链接点击崩溃:需FLAG_ACTIVITY_NEW_TASK?
解决ListView中autoLink="web"点击崩溃问题
我之前也踩过这个坑!问题根源在于:当你在ListView的Item布局里使用android:autoLink="web"时,系统默认的链接跳转逻辑用的是应用级上下文(Application Context),而不是当前Activity的上下文。启动Activity时,非Activity上下文必须加上FLAG_ACTIVITY_NEW_TASK标记,这就导致了崩溃报错。
下面给你两种靠谱的解决方案,都是从「确保用Activity上下文启动Intent」这个核心点出发的:
方案一:自定义TextView重写链接点击逻辑
这种方法适合想保留android:autoLink="web"自动识别链接的场景,只需要替换布局里的TextView为自定义控件:
public class ActivityLinkTextView extends AppCompatTextView { public ActivityLinkTextView(Context context) { super(context); init(); } public ActivityLinkTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ActivityLinkTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 启用链接点击能力 setMovementMethod(LinkMovementMethod.getInstance()); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); // 替换默认的链接点击处理逻辑 if (getMovementMethod() instanceof LinkMovementMethod) { setMovementMethod(new LinkMovementMethod() { @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { int x = (int) event.getX() - widget.getTotalPaddingLeft() + widget.getScrollX(); int y = (int) event.getY() - widget.getTotalPaddingTop() + widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int offset = layout.getOffsetForHorizontal(line, x); URLSpan[] spans = buffer.getSpans(offset, offset, URLSpan.class); if (spans.length > 0) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(spans[0].getURL())); // 这里直接用当前TextView的上下文(也就是Activity上下文)启动 widget.getContext().startActivity(intent); return true; } } return super.onTouchEvent(widget, buffer, event); } }); } } }
然后在你的Item布局里替换:
<com.yourpackage.ActivityLinkTextView android:id="@+id/tv_url" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autoLink="web" />
方案二:在Adapter中手动设置可点击链接
这种方法不需要修改布局,直接在Adapter的getView方法里手动处理链接,灵活性更高:
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_url, parent, false); holder = new ViewHolder(); holder.tvUrl = convertView.findViewById(R.id.tv_url); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 获取当前item的URL数据 String url = mDataList.get(position).getUrl(); // 构建可点击的 SpannableString SpannableString spannableUrl = new SpannableString(url); spannableUrl.setSpan(new ClickableSpan() { @Override public void onClick(View widget) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); // 用parent.getContext()获取Activity上下文启动Intent parent.getContext().startActivity(intent); } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); // 设置链接样式(蓝色+下划线) ds.setColor(Color.parseColor("#2196F3")); ds.setUnderlineText(true); } }, 0, url.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); holder.tvUrl.setText(spannableUrl); holder.tvUrl.setMovementMethod(LinkMovementMethod.getInstance()); return convertView; } static class ViewHolder { TextView tvUrl; }
为什么不推荐加FLAG_ACTIVITY_NEW_TASK?
虽然给Intent加上intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)能暂时解决崩溃,但会把浏览器启动到新的任务栈里,用户按返回键时不会回到你的App,体验很糟糕,所以尽量不用这种方法。
内容的提问来源于stack exchange,提问作者BlueYeti81
相关产品推荐
相关产品推荐

