如何在片段而不是活动中使用 setContentView

Posted

技术标签:

【中文标题】如何在片段而不是活动中使用 setContentView【英文标题】:How to use setContentView in fragment instead of an activity 【发布时间】:2020-07-30 21:26:47 【问题描述】:

亲爱的 ***ers :)

AllAssetsFragment 从 MainActivity 打开。在这个片段中,我无法正确设置 setContentView()getApplicationContext()

我知道有问题。一些代码适用于正常活动,但它们不适用于此片段。

所有资产片段:

import android.content.Intent;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

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 AllAssetsFragment extends Fragment 

    public AllAssetsFragment()


    


    private static final String HI = "https://uniqueandrocode.000webhostapp.com/hiren/favouritelist.php";
    private List<AssetsItem>assetsItems;
    private RecyclerView recyclerView;
    AssetsAdapter adapter;

    private JsonArrayRequest request;
    private RequestQueue requestQueue;
    public static FavoritesDatabase favoritesDatabase;
    Button btn;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 

        return inflater.inflate(R.layout.fragment_allassets, container, false);


        recyclerView = (RecyclerView)getView().findViewById(R.id.recyclerview);
        recyclerView.setHasFixedSize(true);
        // +++ PROBLEM 1: Context doesn't work (same on Problem 3 and 4) +++
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        assetsItems = new ArrayList<>();
        btn=(Button)getView().findViewById(R.id.favbtn);
        btn.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 

                // +++ PROBLEM 2: This code doesn't work to open Fragment from Fragment +++
                startActivity(new Intent(AllAssetsFragment.this, FavoritesFragment.class));
            


        );
        favoritesDatabase = Room.databaseBuilder(getActivity().getApplicationContext(), FavoritesDatabase.class, "myfavdb").allowMainThreadQueries().build();
        getData();

    

    private void getData() 
        request = new JsonArrayRequest(HI, new Response.Listener<JSONArray>() 
            @Override
            public void onResponse(JSONArray response) 
                JSONObject jsonObject = null;
                for (int i = 0; i < response.length(); i++) 
                    try 
                        JSONObject ob = response.getJSONObject(i);
                        AssetsItem pr = new AssetsItem(ob.getInt("id"),
                                ob.getString("product_name"),
                                ob.getString("product_img"));
                        assetsItems.add(pr);

                     catch (JSONException e) 
                        e.printStackTrace();
                    
                
                setupData(assetsItems);
            
        , new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 

            
        );

        // +++ PROBLEM 3: Context doesn't work +++
        requestQueue = Volley.newRequestQueue(this);
        requestQueue.add(request);
    

    private void setupData(List<AssetsItem>assetsItems)
    adapter=new AssetsAdapter(assetsItems,getActivity().getApplicationContext());
    recyclerView.setAdapter(adapter);
    

这里是我们的第二个片段:FavoritesFragment:



import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;


/**
 * A simple @link Fragment subclass.
 */
public class FavoritesFragment extends Fragment 


    public FavoritesFragment() 

    

    private RecyclerView rv;
    private FavoritesAdapter adapter;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 

        return inflater.inflate(R.layout.fragment_favorites, container, false);

        rv=(RecyclerView)getView().findViewById(R.id.rec);
        rv.setHasFixedSize(true);
        // +++ PROBLEM 4: doesn't work +++
        rv.setLayoutManager(new LinearLayoutManager(this));

        getFavData();
    

    private void getFavData()
        List<FavoritesItem>favoritesItems=AllAssetsFragment.favoritesDatabase.favoritesDao().getFavoritesData();

        adapter = new FavoritesAdapter(favoritesItems,getActivity().getApplicationContext());
        rv.setAdapter(adapter);
    




【问题讨论】:

请不要仅仅因为您使用 android-studio 标签而标记问题:Android Studio 标签应该在您对 IDE 本身有疑问时使用,而不是您在其中编写(或想要编写)的任何代码。请参阅 when is it appropriate to remove an IDE tag、How do I avoid misusing tags? 和 the tagging guide。请改用 [android] 或其他相关标签。 【参考方案1】:

不要在片段中使用setContentView()。你应该在onCreateView() 中初始化你的视图,就像你已经做的那样。

关于应用程序上下文,我看到您正在将它传递给您的适配器。我认为您不需要那里的应用程序上下文,因为片段的上下文就足够了。你可以传requireContext()

您还需要从onCreateView() 设置您的RecyclerView 和适配器。

【讨论】:

感谢您的建议,我在上面的代码中添加了它,但仍然有 3 个上下文问题和 1 个从现有片段打开片段的问题。为了使它更容易,我用第二个片段添加到上面的代码中。如果你能解决这些问题,那就太好了! :) @Lulu96 我同意 Minas Mina 的观点。最近Android Studio的lint推荐使用requireContext来获取一个Context。尝试将getActivity().getApplicationContext()this 替换为requireContext()【参考方案2】:

这些是您在代码中犯的错误。

AllAssetsFragment

将下面的行移到onCreateView() 方法的底部。它是一个 return 语句,因此,它必须是函数中的最后一件事。

return inflater.inflate(R.layout.fragment_allassets, container, false);

您不能使用startActivity(...) 来启动片段。此方法严格用于启动活动。要了解如何启动片段,请查看this awesome answer。

将下面几行中的this 替换为getActivity()

recyclerView.setLayoutManager(new LinearLayoutManager(this));requestQueue = Volley.newRequestQueue(this);

收藏片段

将下面一行中的this 替换为getActivity()

rv.setLayoutManager(new LinearLayoutManager(this));

附录:

要在活动(在您的情况下为 MainActivity)中启动片段,请执行以下步骤:

    在您的 activity_main.xml 文件中,创建一个 FrameLayout 来容纳您的片段,您可以给它一个 id:container。如果您不知道如何执行此操作,只需粘贴以下代码:

    <FrameLayout
        android:layout_
        android:layout_
        android:id="@+id/container" />
    

    当你想从一个活动中启动一个片段时,只需使用这个代码sn-p:

    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.container, new AllAssetsFragment());
    transaction.commit();
    

    当你想从另一个 Fragment 启动一个 Fragment 时,只需使用这段代码 sn-p:

    FragmentTransaction transaction = getActivity().getFragmentManager().beginTransaction();
    transaction.replace(R.id.container, new AllAssetsFragment());
    transaction.commit();
    

    在上面的代码 sn-ps 中,如果 getFragmentManager() 不起作用或者您使用的是 AndroidX,请改用 getSupportFragmentManager()

【讨论】:

所有其他建议都很好!但我不知道如何启动AllAssetsFragmentFavoritesFragment 课程。重要提示:它们已经使用下面代码中的名称制作。只有这一行是错的,你能帮我写一个有效的吗? ;) 谢谢! startActivity(getActivity(AllAssetsFragment, FavoritesFragment.class)); 我已经更新了我的答案。我添加了一些关于如何启动片段的步骤。 如果有什么问题,请告诉我。我会解释的。【参考方案3】:

您不要在需要在onCreateView 方法中返回视图的片段中调用setContentView。你已经完成了。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) 
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_allassets, container, false);

对于getApplicationContext,您需要致电getActivity()

喜欢这个

getActivity().getApplicationContext()

【讨论】:

感谢您的建议,我在上面的代码中添加了它,但仍然有 3 个上下文问题和 1 个从现有片段打开片段。

以上是关于如何在片段而不是活动中使用 setContentView的主要内容,如果未能解决你的问题,请参考以下文章

如何让自定义视图观察包含片段的生命周期事件而不是活动?

为啥使用片段,以及何时使用片段而不是活动?

根据字符串名称而不是列表视图项位置替换片段并启动活动

在导航抽屉上调用不是片段活动的活动

使用单个片段显示UI而不是活动是一种好习惯吗?

android如何使用listview而不是scrollview