英文:
RecyclerView Adapter OnClickListener crashes: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
问题
我明白你的问题,你想要解决你的Android Studio项目中的问题。你的代码中有一些小问题,我将为你指出并提供一些改进建议。
- 在
Adapter.java
的ViewHolder
中,你尝试在onClick
方法中启动一个Intent
来打开一个网页链接。但是,你需要为Intent
添加FLAG_ACTIVITY_NEW_TASK
标志。这是因为你在ViewHolder
类中调用startActivity
,而不是在一个活动(Activity)中。你可以这样修改代码:
artTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 添加此标志
context.startActivity(intent);
}
});
- 你在
MainActivity.java
中使用了JSON_URL
变量,但没有为其提供一个有效的JSON链接。确保将其替换为你实际使用的JSON链接,例如:
private static String JSON_URL = "https://example.com/your_json_file.json";
- 请确保在AndroidManifest.xml文件中添加了Internet权限,以便应用可以访问网络。你可以在
<manifest>
标签内添加以下代码:
<uses-permission android:name="android.permission.INTERNET" />
这些改进应该能帮助你解决一部分问题。如果你仍然遇到问题,请提供更多详细信息,以便我能够提供更多帮助。
英文:
I am new to Android Studio and starting learning via a project of mine. I realize this question has been asked so many times over the last years but I have read most of them and could not fix my code.
The idea is to parse a list from an online JSON file and make clickable cards that take the user to the associated link.
I managed to get the cards on screen but the app crashes the moment the card is clicked. I also (think that I) understand that this problem could arise when I use a secondary layout xml and the objects are in the wrong place.
My MainActivity.java: (you might see some variable names are off-topic, I am using a template to get my first project running)
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);
}
}
My Adapter.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);
}
});
}
}
}
My 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>
and my custom layout 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>
and the stack trace:
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)
I placed www.google.com as a placeholder link. I need to get each associated link from the JSON file.
I'd be happy if you could point me in the right direction.
答案1
得分: 2
你可以按照此答案所说的方式绕过这个问题,但这样做会在涉及到后退堆栈和多任务处理时产生不希望的副作用。你问题的真正根本原因是你在适配器中使用了getApplicationContext()
,而你应该传递的是你的Activity
:
adapter = new Adapter(getApplicationContext(), songs);
你应该将上面的行替换为:
adapter = new Adapter(MainActivity.this, songs);
英文:
You can work around the issue by passing the flag as this answer says, but that will have undesired side effects when it comes to your back stack and multitasking. The actual root cause of your problem is that you're using passing getApplicationContext()
to your Adapter when you should be passing your Activity
:
adapter = new Adapter(getApplicationContext(),songs);
You should replace the above line with:
adapter = new Adapter(MainActivity.this,songs);
答案2
得分: 1
你需要在你的意图中添加一个标志。你可以从堆栈跟踪中查看具体是哪一个标志。
artTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
这是标志:
android.util.AndroidRuntimeException: 从活动外部调用startActivity()需要 **FLAG_ACTIVITY_NEW_TASK** 标志。这真的是你想要的吗?
希望这能有所帮助!
英文:
You have to add a flag to your intent. You can check which one from the stacktrace.
artTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Here is the Flag
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the **FLAG_ACTIVITY_NEW_TASK** flag. Is this really what you want?
Hope this helps!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论