RecyclerView Adapter OnClickListener crashes: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag

huangapple go评论78阅读模式
英文:

RecyclerView Adapter OnClickListener crashes: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag

问题

我明白你的问题,你想要解决你的Android Studio项目中的问题。你的代码中有一些小问题,我将为你指出并提供一些改进建议。

  1. Adapter.javaViewHolder中,你尝试在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);
    }
});
  1. 你在MainActivity.java中使用了JSON_URL变量,但没有为其提供一个有效的JSON链接。确保将其替换为你实际使用的JSON链接,例如:
private static String JSON_URL = "https://example.com/your_json_file.json";
  1. 请确保在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&lt;Song&gt; songs;
    private static String JSON_URL = &quot;JSON LINK&quot;;
    Adapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.songsList);
        songs = new ArrayList&lt;&gt;();
        extractSongs();
    }

    private void extractSongs() {
        RequestQueue queue = Volley.newRequestQueue(this);
        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, JSON_URL, null, new Response.Listener&lt;JSONArray&gt;() {
            @Override
            public void onResponse(JSONArray response) {
                for (int i = 0; i &lt; response.length(); i++) {
                    try {
                        JSONObject songObject = response.getJSONObject(i);

                        Song song = new Song();
                        song.setTitle(songObject.getString(&quot;title&quot;).toString());
                        song.setLink(songObject.getString(&quot;link&quot;));
                        song.setJournal(songObject.getString(&quot;journal&quot;.toString()));
                        song.setDate(songObject.getString(&quot;date&quot;));
                        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(&quot;tag&quot;, &quot;onErrorResponse: &quot; + 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&lt;Adapter.ViewHolder&gt; {
    LayoutInflater inflater;
    List&lt;Song&gt; songs;

    Context context;

    public Adapter(Context ctx, List&lt;Song&gt; 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(&quot;https://www.google.com&quot;));
                    context.startActivity(intent);
                }
            });

        }
    }
}

My activity_main.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;androidx.recyclerview.widget.RecyclerView
        android:id=&quot;@+id/songsList&quot;
        android:layout_width=&quot;0dp&quot;
        android:layout_height=&quot;0dp&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;

and my custom layout xml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;&gt;

    &lt;androidx.cardview.widget.CardView
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginStart=&quot;8dp&quot;
        android:layout_marginTop=&quot;8dp&quot;
        android:layout_marginEnd=&quot;8dp&quot;
        android:layout_marginBottom=&quot;8dp&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:layout_constraintTop_toTopOf=&quot;parent&quot;&gt;

        &lt;androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;&gt;
            &lt;TextView
                android:id=&quot;@+id/artDate&quot;
                android:layout_width=&quot;match_parent&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:text=&quot;DATE&quot;
                app:layout_constraintStart_toStartOf=&quot;parent&quot;
                app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;

            &lt;TextView
                android:id=&quot;@+id/artTitle&quot;
                android:layout_width=&quot;0dp&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:layout_marginStart=&quot;16dp&quot;
                android:layout_marginTop=&quot;8dp&quot;
                android:text=&quot;ARTICLE TITLE&quot;
                android:textSize=&quot;18sp&quot;
                android:textStyle=&quot;bold&quot;
                app:layout_constraintTop_toBottomOf=&quot;@+id/artDate&quot; /&gt;

            &lt;TextView
                android:id=&quot;@+id/artJournal&quot;
                android:layout_width=&quot;0dp&quot;
                android:layout_height=&quot;wrap_content&quot;
                android:layout_marginStart=&quot;16dp&quot;
                android:text=&quot;Journal Name&quot;
                app:layout_constraintTop_toBottomOf=&quot;@+id/artTitle&quot; /&gt;

        &lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
    &lt;/androidx.cardview.widget.CardView&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;

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(&quot;https://www.google.com&quot;));
                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!

huangapple
  • 本文由 发表于 2020年5月19日 21:23:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/61892145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定