Reputation: 541
Why does my Android Adapter not have the getActivity() method ? and yet many tutorials out there have access to the getActivity() method inside lets say recyclerview Adapters
I already tried passing the getActivity() from a fragment using the constructor but still does not accomplish what i want.
My Fragment that calls the Adapter
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.
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());
}
}
Upvotes: 13
Views: 25457
Reputation: 1789
create constructor in 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
notesAdapter = new NotesAdapter(notes,getActivity());
Upvotes: 0
Reputation: 257
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. This wont create any memory references. you can avoid the memory leakage.
Upvotes: 0
Reputation: 1806
It doesn't have it because there is no use of Context
internal to Adapter
. Context
is used when you need it for a specific app wide side effect or resource retrieval.
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 (i.e strings.xml
) or some factory which provides utility. 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.
One simple way to achieve that is to define an interface with a single method that returns a Context
.
interface ContextProvider {
Context getContext();
}
Then whoever allocates a new Adapter
of yours (i.e an Activity
, a Fragment
) can forward its Context
via the provider interface.
// 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())
. It will leak due to retaining it in a property when your app returns to home screen.
Upvotes: 5
Reputation: 96
notesAdapter = new NotesAdapter(notes, getActivity());
then use that reference inside your adapter.
Upvotes: 0
Reputation: 11
Another way to accomplish it by creating a static instance of fragment like
static NotesFragment note_instance;
and on onCreate assign value
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();
Upvotes: -1
Reputation: 698
You can pass Context around to you adapter, but you cannot access the getActivity() method from an inner class.
Add a method, or place Context as a parameter in your constructor:
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 (i.e. a refreshViews() method), you can check the class and use casting:
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.
Upvotes: 15
Reputation: 110
Only a fragment object can make a call to 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.
From the android developers documentation
Activity getActivity () Return the Activity this fragment is currently associated with.
Upvotes: 0