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());
}
}
getActivity() in a Fragment returns the Activity the Fragment is currently associated with. (see http://developer.android.com/reference/android/app/Fragment.html#getActivity()). getActivity() is user-defined.
If you have a custom adapter, change the constructor to require Context as a parameter. Then, create an Instance variable to store the context via the constructor. And now you can use the variable mContext from anywhere in your adapter.
Android provides several subclasses of Adapter that are useful for retrieving different kinds of data and building views for an AdapterView ( i.e. ListView or GridView). The common adapters are ArrayAdapter,Base Adapter, CursorAdapter, SimpleCursorAdapter,SpinnerAdapter and WrapperListAdapter.
An adapter basically connects the User Interfaces and the Data Source. According to Android officials, “An Adapter object acts as a bridge between an AdapterView and the data for that view. Android Adapters basically provides access to the data items.”
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With