java - RecyclerView 适配器 OnClickListener 崩溃:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志
问题描述
我是 Android Studio 的新手,并通过我的一个项目开始学习。我意识到这个问题在过去几年中被问了很多次,但我已经阅读了其中的大部分内容并且无法修复我的代码。
这个想法是从在线 JSON 文件中解析一个列表,并制作可点击的卡片,将用户带到相关链接。
我设法将卡片显示在屏幕上,但在点击卡片的那一刻应用程序崩溃了。我也(认为我)明白,当我使用辅助布局 xml 并且对象位于错误的位置时,可能会出现此问题。
我的 MainActivity.java :(您可能会看到一些变量名离题,我正在使用模板来运行我的第一个项目)
package net.smallacademy.songslist;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<Song> songs;
private static String JSON_URL = "JSON LINK";
Adapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.songsList);
songs = new ArrayList<>();
extractSongs();
}
private void extractSongs() {
RequestQueue queue = Volley.newRequestQueue(this);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, JSON_URL, null, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject songObject = response.getJSONObject(i);
Song song = new Song();
song.setTitle(songObject.getString("title").toString());
song.setLink(songObject.getString("link"));
song.setJournal(songObject.getString("journal".toString()));
song.setDate(songObject.getString("date"));
songs.add(song);
} catch (JSONException e) {
e.printStackTrace();
}
}
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
adapter = new Adapter(getApplicationContext(),songs);
recyclerView.setAdapter(adapter);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("tag", "onErrorResponse: " + error.getMessage());
}
});
queue.add(jsonArrayRequest);
}
}
我的适配器.java:
package net.smallacademy.songslist;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.android.volley.AuthFailureError;
import org.w3c.dom.Text;
import java.util.List;
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
LayoutInflater inflater;
List<Song> songs;
Context context;
public Adapter(Context ctx, List<Song> songs){
this.inflater = LayoutInflater.from(ctx);
this.songs = songs;
this.context = ctx;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_list_layout,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
// bind the data
holder.artTitle.setText(songs.get(position).getTitle());
holder.artJournal.setText(songs.get(position).getJournal());
holder.artDate.setText(songs.get(position).getDate());
}
@Override
public int getItemCount() {
return songs.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView artTitle,artJournal,artDate,artLink;
Button buttonVisit;
public ViewHolder(@NonNull View itemView) {
super(itemView);
artTitle = itemView.findViewById(R.id.artTitle);
artJournal = itemView.findViewById(R.id.artJournal);
artDate = itemView.findViewById(R.id.artDate);
// handle onClick
artTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
context.startActivity(intent);
}
});
}
}
}
我的activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/songsList"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
和我的自定义布局 xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/artDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="DATE"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/artTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="ARTICLE TITLE"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/artDate" />
<TextView
android:id="@+id/artJournal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Journal Name"
app:layout_constraintTop_toBottomOf="@+id/artTitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
和堆栈跟踪:
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:952)
at android.app.ContextImpl.startActivity(ContextImpl.java:928)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:383)
at net.smallacademy.songslist.Adapter$ViewHolder$1.onClick(Adapter.java:81)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
我将 www.google.com 作为占位符链接。我需要从 JSON 文件中获取每个关联的链接。
如果你能指出我正确的方向,我会很高兴。
解决方案
你可以通过传递标志来解决这个问题,但是当涉及到你的后台堆栈和多任务处理时,这会产生不希望的副作用。问题的实际根本原因是您在getApplicationContext()
应该传递时使用传递给适配器Activity
:
adapter = new Adapter(getApplicationContext(),songs);
您应该将上面的行替换为:
adapter = new Adapter(MainActivity.this,songs);
推荐阅读
- python - MyPy 为字典抛出“分配中不兼容的类型”错误
- typescript - 如何获得打字稿节点应用程序的集成测试覆盖率?
- sql - PostgreSQL:计算列中真值的出现次数
- java - 如何为 spring 5 实现 log4j2 的配置文件
- paypal - PayPal 订阅的区域销售税 React-js
- c++ - 编码正确逻辑时输出不正确的原因?
- c++ - 如何在头文件中引用?
- firebase - Flutter firebase 通知点击打开一个屏幕
- c - sscanf C 中包含可变长度字符串和数字的字符串
- amazon-web-services - 如何从 aws s3 下载大文件