简体   繁体   English

为什么我的 Android Adapter 没有 getActivity() 方法

[英]Why does my Android Adapter not have the getActivity() method

Why does my Android Adapter not have the getActivity() method ?为什么我的 Android Adapter 没有 getActivity() 方法? and yet many tutorials out there have access to the getActivity() method inside lets say recyclerview Adapters然而,许多教程都可以访问内部的 getActivity() 方法,比如 recyclerview Adapters

I already tried passing the getActivity() from a fragment using the constructor but still does not accomplish what i want.我已经尝试使用构造函数从片段传递 getActivity() 但仍然没有完成我想要的。

My Fragment that calls the Adapter我的 Fragment 调用适配器

package layout;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import com.example.elm.login.Navigation;
import com.example.elm.login.R;
import com.example.elm.login.adapter.NotesAdapter;
import com.example.elm.login.model.Note;
import com.example.elm.login.services.note.UploadNote;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link NotesFragment.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link NotesFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class NotesFragment extends Fragment {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

private OnFragmentInteractionListener mListener;

public List<Note> notes = new ArrayList<>();
private RecyclerView recyclerView;
public NotesAdapter notesAdapter;

public NotesFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment NotesFragment.
 */
// TODO: Rename and change types and number of parameters
public static NotesFragment newInstance(String param1, String param2) {
    NotesFragment fragment = new NotesFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

private UploadReceiver receiver;
private SyncReceiver syncReceiver;

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

    //register broadcast receiver
    IntentFilter filter = new IntentFilter(UploadNote.ACTION_RESP);
    //filter.addCategory(Intent.CATEGORY_DEFAULT);
    receiver = new UploadReceiver();
    getActivity().registerReceiver(receiver, filter);

    IntentFilter intentFilter = new IntentFilter(SyncReceiver.SYNC_ACTION);
    syncReceiver = new SyncReceiver();
    getActivity().registerReceiver(syncReceiver, intentFilter);

    recyclerView = (RecyclerView) view.findViewById(R.id.notes_recycler);
    notes = Note.find(Note.class, null,null,null,"noteid DESC", null);

    notesAdapter = new NotesAdapter(notes);

    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    recyclerView.setAdapter(notesAdapter);


    return  view;
    //return inflater.inflate(R.layout.fragment_notes2, container, false);
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}



 /* @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

*/

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}

@Override
public void onResume() {
    super.onResume();

}

/**
 * redraw the recycler -view --all of it
 */

public void addNew(Note note){
    if (notesAdapter!=null){
        notesAdapter.newData(note);
        recyclerView.smoothScrollToPosition(0);

    }
}

public void update(Note note){
    if (notesAdapter!=null){
        notesAdapter.updateItem(note);
    }
}

/**
 * receive broadcasts
 */
public class UploadReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("vane", "vane");
        Bundle bundle = intent.getExtras();
        String newNote = bundle.getString("note");
        Gson gson = new Gson();
        Type type = new TypeToken<Note>(){
        }.getType();
        Note note = gson.fromJson(newNote, type);
        addNew(note);

    }
}
public class SyncReceiver extends BroadcastReceiver{
    public static final String SYNC_ACTION = "sync_action";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("received_sync", "yes");
        Bundle bundle = intent.getExtras();
        String newNote = bundle.getString("note");
        Gson gson = new Gson();
        Type type = new TypeToken<Note>(){
        }.getType();
        Note note = gson.fromJson(newNote, type);
        update(note);

    }
}

} }

and my Adapter: in which i cant declare an instance of getActivity method.和我的 Adapter: 在其中我不能声明 getActivity 方法的实例。

package com.example.elm.login.adapter;

import android.content.Context;
import android.content.Intent;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.bignerdranch.android.multiselector.SwappingHolder;
import com.example.elm.login.FullNote;
import com.example.elm.login.Navigation;
import com.example.elm.login.R;
import com.example.elm.login.model.Note;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by elm on 7/17/17.
 */

public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.myViewHolder> {
    private Context context;
    public List<Note> allnotes;
    private MultiSelector multiSelector = new MultiSelector();
    private ModalMultiSelectorCallback modalMultiSelectorCallback = new ModalMultiSelectorCallback(multiSelector) {
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            return super.onCreateActionMode(actionMode, menu);
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        return false;
    }
};

public NotesAdapter(List<Note> allnotes) {
    this.allnotes = allnotes;
}

@Override
public NotesAdapter.myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.activity_note_card, parent, false);
    return new myViewHolder(view);
}

@Override
public void onBindViewHolder(NotesAdapter.myViewHolder holder, int position) {
    //context = holder
    Note notes = allnotes.get(position);
    holder.title.setText(notes.getTitle());
    holder.note.setText(notes.getNote());
    if (notes.getUploadflag()){
        holder.imageView.setImageResource(R.mipmap.ic_cloud);
    }else {
        holder.imageView.setImageResource(R.mipmap.ic_cloud_done);
    }
}

@Override
public int getItemCount() {
    return allnotes.size();
}

public class myViewHolder extends SwappingHolder{
    public TextView title, note;
    public ImageView imageView;

    public myViewHolder(View itemView) {
        super(itemView, multiSelector);
        title = (TextView) itemView.findViewById(R.id.card_title);
        note = (TextView) itemView.findViewById(R.id.card_note);
        imageView = (ImageView) itemView.findViewById(R.id.uploadstatus);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int pos = getLayoutPosition();
                Note note = allnotes.get(pos);
                Intent intent = new Intent(v.getContext(), FullNote.class);
                intent.putExtra("noteId", note.getId());
                v.getContext().startActivity(intent);
            }
        });

        itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {

                if (!multiSelector.isSelectable()){
                    ((AppCompatActivity) v.getContext()).startSupportActionMode(modalMultiSelectorCallback);
                    multiSelector.setSelectable(true);
                    multiSelector.setSelected(myViewHolder.this, true);
                    return true;
                }
                return false;
            }
        });
    }
}

public void swapAll(List<Note> notes){
    allnotes.clear();
    allnotes.addAll(notes);
    this.notifyDataSetChanged();
}

public void newData(Note note){
    this.allnotes.add(0, note);
    notifyItemInserted(0);
    notifyItemRangeChanged(0, allnotes.size());
}

public void updateItem(Note note){
    Log.e("atview", String.valueOf(note.getId()));
    Note data = null;
    for (Note n: allnotes){
        Log.e("id", String.valueOf(n.getId()));
        if (n.getId().equals(note.getId())){
            Log.e("found", String.valueOf(allnotes.indexOf(n)));
            int position = allnotes.indexOf(n);

            allnotes.remove(position);
            notifyItemRemoved(position);
            notifyItemRangeChanged(position, allnotes.size());

            allnotes.add(position, note);
            notifyItemInserted(position);
            notifyItemRangeChanged(position, allnotes.size());


            break;
        }
    }
}

public void removeItem(int position){
    allnotes.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, allnotes.size());
}

} }

You can pass Context around to you adapter, but you cannot access the getActivity() method from an inner class.您可以将 Context 传递给适配器,但不能从内部类访问 getActivity() 方法。

Add a method, or place Context as a parameter in your constructor:添加方法,或将 Context 作为参数放置在构造函数中:

addContext(Context context);

When you initialize the adapter you can call your new method初始化适配器时,您可以调用新方法

myAdapter.addContext(MyActivity.this);

If you want to call activity specific methods (ie a refreshViews() method), you can check the class and use casting:如果要调用特定于活动的方法(即 refreshViews() 方法),可以检查类并使用强制转换:

if (context.getClass().equals(MyActivity.class)) {
    ((MyActivity) context).refreshView();
}

Edit:: Be sure to clear your references to context when you are done with your adapter to avoid memory leaks.编辑:: 确保在完成适配器后清除对上下文的引用以避免内存泄漏。

It doesn't have it because there is no use of Context internal to Adapter .它没有它,因为没有使用Adapter内部的Context Context is used when you need it for a specific app wide side effect or resource retrieval.当您需要它来处理特定的应用程序范围的副作用或资源检索时,将使用Context

When you find a code piece which uses Context inside of an Adapter , you will notice it uses that Context for either creating a View , getting a resource from XML files (ie strings.xml ) or some factory which provides utility.当您在Adapter找到使用Context的代码段时,您会注意到它使用该Context来创建View 、从 XML 文件(即strings.xml )或某些提供实用程序的工厂获取资源。 Those code examples are written that way to provide clarity.这些代码示例以这种方式编写以提供清晰性。

An actual Adapter implementor is expected to know those use cases and implement her own solution via either acquiring the Context from the instantiator of the Adapter or via coding her own indirection for the retrieved resource and/or utility.实际的Adapter实现者应该知道这些用例并通过从Adapter的实例化Adapter获取Context或通过为检索到的资源和/或实用程序编写自己的间接寻址来实现她自己的解决方案。

One simple way to achieve that is to define an interface with a single method that returns a Context .实现这一目标的一种简单方法是使用返回Context的单个方法定义接口。

interface ContextProvider {
    Context getContext();
}

Then whoever allocates a new Adapter of yours (ie an Activity , a Fragment ) can forward its Context via the provider interface.那么无论谁分配了你的新Adapter (即一个Activity ,一个Fragment )都可以通过提供者接口转发它的Context

// Your MyActivity.java or MyFragment.java
MyAdapter anAdapter = new MyAdapter(new ContextProvider {
    @Override
    public Context getContext() {
        return getActivity(); // For fragments
        return MyActivity.this; // For activities
    }
});

// MyAdapter.java
class MyAdapter extends SomeAdapterFromSDK {
    private final ContextProvider mContextProvider;

    public MyAdapter(ContextProvider cp) {
        mContextProvider = cp;
    }

    public void someAdapterMethod() {
        Context c = mContextProvider.getContext();
        // Use c as your context (i.e c.getString(R.string.message))
    }
}

Huge disclaimer: Don't pass your Context directly like new Adapter(getActivity()) .巨大的免责声明:不要像new Adapter(getActivity())那样直接传递你的Context It will leak due to retaining it in a property when your app returns to home screen.当您的应用返回主屏幕时,它会因为将其保留在属性中而泄漏。

Only a fragment object can make a call to getActivity().只有片段对象可以调用 getActivity()。 If you may have come across tutorials that make use of getActivity() inside an adapter I think what they are trying to convey is for you to replace getActivity() with an activity reference.如果您可能遇到过在适配器中使用 getActivity() 的教程,我认为他们试图传达的是让您将 getActivity() 替换为活动引用。

From the android developers documentation来自 android 开发者文档

Activity getActivity () Return the Activity this fragment is currently associated with. Activity getActivity() 返回当前与此片段关联的 Activity。

notesAdapter = new NotesAdapter(notes, getActivity());

然后在您的适配器中使用该引用。

You can access the members and methods of activity by introducing interface between them.您可以通过在它们之间引入接口来访问活动的成员和方法。

interface ActivityInterface {
     public Context getPresentActivityContext();
}

In Activity,在活动中,

Class Activity implements ActivityInterface {

      .....
      .....
      @Override
      public Context getPresentActivityContext() {
           return getApplicationContext();
      }
      .....
      .....
      adapter.setActivityInterface(this);
}

In Adapter,在适配器中,

private ActivityInterface activityInterface;

public void setActivityInterface(ActivityInterface activityInterface) {
     this.activityInterface = activityInterface;
}

After this, You can directly access the context using activityInterface.getPresentActivityContext() in your adapter.在此之后,您可以使用适配器中的activityInterface.getPresentActivityContext()直接访问上下文。 This wont create any memory references.这不会创建任何内存引用。 you can avoid the memory leakage.您可以避免内存泄漏。

create constructor in Adapter.在 Adapter 中创建构造函数。

public NotesAdapter(List<Note> allnotes) {
    this.allnotes = allnotes;
}

to

Activity mActivity;
//....
public NotesAdapter(List<Note> allnotes,Activity mActivity) {
this.allnotes = allnotes;
this.mActivity = mActivity;
}

Try to change in NotesFragment尝试在 NotesFragment 中更改

notesAdapter = new NotesAdapter(notes,getActivity());

Another way to accomplish it by creating a static instance of fragment like另一种通过创建片段的静态实例来完成它的方法,例如

static NotesFragment note_instance;

and on onCreate assign value和 onCreate 赋值

note_fragment=this;

You can create a static method to get the instance like您可以创建一个静态方法来获取实例

public static NotesFragment getInstance (){
return note_fragment;
}

and then you can do anything to the recent fragment instance but be sure to check if the instance is not null to avoid null pointer exception You can access the method by然后您可以对最近的片段实例执行任何操作,但请务必检查该实例是否为空以避免空指针异常您可以通过以下方式访问该方法

NotesFragment.getInstance();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM