I'm using this code to call a CameraFragment using this library https://github.com/florent37/CameraFragment
Here is the MyCameraFragment.java code :
public class MyCameraFragment extends Fragment {
public static final String FRAGMENT_TAG = "camera";
private static final int REQUEST_CAMERA_PERMISSIONS = 931;
#Bind(R.id.action_settings)
CameraSettingsView settingsView;
#Bind(R.id.flash_switch_view)
FlashSwitchView flashSwitchView;
#Bind(R.id.front_back_camera_switcher)
CameraSwitchView cameraSwitchView;
#Bind(R.id.record_button)
RecordButton recordButton;
#Bind(R.id.cameraLayout)
View cameraLayout;
private FragmentActivity myContext;
public MyCameraFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
* #return A new instance of fragment MyCameraFragment.
*/
public static MyCameraFragment newInstance() {
MyCameraFragment fragment = new MyCameraFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String[] permissions = {
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE};
final List<String> permissionsToRequest = new ArrayList<>();
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) {
permissionsToRequest.add(permission);
}
}
if (!permissionsToRequest.isEmpty()) {
ActivityCompat.requestPermissions(getActivity(), permissionsToRequest.toArray(new String[permissionsToRequest.size()]), REQUEST_CAMERA_PERMISSIONS);
} else addCamera();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_camera, container, false);
ButterKnife.bind(getActivity(),view);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#OnClick(R.id.flash_switch_view)
public void onFlashSwitcClicked() {
final CameraFragmentApi cameraFragment = getCameraFragment();
if (cameraFragment != null) {
cameraFragment.toggleFlashMode();
}
}
#OnClick(R.id.front_back_camera_switcher)
public void onSwitchCameraClicked() {
final CameraFragmentApi cameraFragment = getCameraFragment();
if (cameraFragment != null) {
cameraFragment.switchCameraTypeFrontBack();
}
}
#OnClick(R.id.record_button)
public void onRecordButtonClicked() {
final CameraFragmentApi cameraFragment = getCameraFragment();
if (cameraFragment != null) {
cameraFragment.takePhotoOrCaptureVideo(new CameraFragmentResultListener() {
#Override
public void onVideoRecorded(String filePath) {
}
#Override
public void onPhotoTaken(byte[] bytes, String filePath) {
Toast.makeText(getActivity(), "onPhotoTaken " + filePath, Toast.LENGTH_SHORT).show();
}
},
"/storage/self/primary",
"photo");
}
}
#OnClick(R.id.settings_view)
public void onSettingsClicked() {
final CameraFragmentApi cameraFragment = getCameraFragment();
if (cameraFragment != null) {
cameraFragment.openSettingDialog();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length != 0) {
addCamera();
}
}
public void addCamera() {
final CameraFragment cameraFragment = CameraFragment.newInstance(new Configuration.Builder()
.setCamera(Configuration.CAMERA_FACE_REAR).build());
getFragmentManager().beginTransaction()
.replace(R.id.content, cameraFragment,FRAGMENT_TAG)
.commitAllowingStateLoss();
if (cameraFragment != null) {
cameraFragment.setStateListener(new CameraFragmentStateListener() {
#Override
public void onCurrentCameraBack() {
cameraSwitchView.displayBackCamera();
}
#Override
public void onCurrentCameraFront() {
cameraSwitchView.displayFrontCamera();
}
#Override
public void onFlashAuto() {
flashSwitchView.displayFlashAuto();
}
#Override
public void onFlashOn() {
flashSwitchView.displayFlashOn();
}
#Override
public void onFlashOff() {
flashSwitchView.displayFlashOff();
}
#Override
public void onCameraSetupForPhoto() {
recordButton.displayPhotoState();
flashSwitchView.setVisibility(View.VISIBLE);
}
#Override
public void onCameraSetupForVideo() {
}
#Override
public void onRecordStateVideoReadyForRecord() {
}
#Override
public void onRecordStateVideoInProgress() {
}
#Override
public void shouldRotateControls(int degrees) {
ViewCompat.setRotation(cameraSwitchView, degrees);
ViewCompat.setRotation(flashSwitchView, degrees);
}
#Override
public void onStartVideoRecord(File outputFile) {
}
#Override
public void onRecordStatePhoto() {
recordButton.displayPhotoState();
}
#Override
public void onStopVideoRecord() {
settingsView.setVisibility(View.VISIBLE);
}
});
cameraFragment.setControlsListener(new CameraFragmentControlsListener() {
#Override
public void lockControls() {
cameraSwitchView.setEnabled(false);
recordButton.setEnabled(false);
settingsView.setEnabled(false);
flashSwitchView.setEnabled(false);
}
#Override
public void unLockControls() {
cameraSwitchView.setEnabled(true);
recordButton.setEnabled(true);
settingsView.setEnabled(true);
flashSwitchView.setEnabled(true);
}
#Override
public void allowCameraSwitching(boolean allow) {
cameraSwitchView.setVisibility(allow ? View.VISIBLE : View.GONE);
}
#Override
public void allowRecord(boolean allow) {
recordButton.setEnabled(allow);
}
#Override
public void setMediaActionSwitchVisible(boolean visible) {
}
});
}
}
private CameraFragmentApi getCameraFragment() {
return (CameraFragmentApi) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}
Here is fragment_camera.xml Code :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.team31.plantdetection.fragments.MyCameraFragment">
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout
android:id="#+id/cameraLayout"
android:visibility="visible"
tools:visibility="visible"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingTop="10dp">
<com.github.florent37.camerafragment.widgets.CameraSettingsView
android:id="#+id/settings_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
/>
<com.github.florent37.camerafragment.widgets.FlashSwitchView
android:id="#+id/flash_switch_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true" />
<com.github.florent37.camerafragment.widgets.CameraSwitchView
android:id="#+id/front_back_camera_switcher"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
/>
</RelativeLayout>
<!--android:background="#82000000"-->
<RelativeLayout
android:id="#+id/record_panel"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#android:color/transparent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<com.github.florent37.camerafragment.widgets.RecordButton
android:id="#+id/record_button"
android:layout_width="75dp"
android:layout_height="75dp"
android:layout_centerInParent="true"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp" />
</RelativeLayout>
</RelativeLayout>
The app crush on launching with the problem : Attempt to ## Heading ##invoke virtual method 'void com.github.florent37.camerafragment.widgets.FlashSwitchView.displayFlashAuto()' on a null object reference
See the Doc
in gradle:
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
in code:
use ButterKnife.bind(this, view); instead of ButterKnife.bind(getActivity(),view);
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
EDIT
use #BindView(R.id.button1) Button button1;
As an alternative to this answer, bear in mind that onCreate is called before onCreateView.
If you have code before the ButterKnife is bound it will obviously be null, I ran into issues as I didn't bother looking up the lifecycle when converting an Activity.
Related
I was testing my app on many device and it was working fine...Untill I tested on an android device running android 7.1 the recycler view is gone while it exists on other devices tahte my Code:
RecyclerGridLayoutAdapter:
public class RecyclerGridLayoutAdapter extends RecyclerView.Adapter<RecyclerGridLayoutAdapter.ViewHolder>{
private int resource;
private ArrayList<Item> contacts;
private TreeMap<String,ArrayList<Contact>> gridsMap;
private String searchedString;
private Context activity;
private String myNumber;
public RecyclerGridLayoutAdapter(int resource, ArrayList<Item> contacts,Context activity) {
this.resource = resource;
this.contacts = contacts;
this.activity=activity;
gridsMap= DatabaseHandler.getDataBaseHandler(activity).getContactsByAlphabets();
loadData();
searchedString="";
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
v= LayoutInflater.from(activity).inflate(resource,parent,false);
ViewHolder vh=new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Log.wtf("begin ","inserting "+contacts.get(position).type);
if(contacts.get(position).type==0){
holder.header.setVisibility(View.VISIBLE);
holder.header.setText(contacts.get(position).alphabet);
holder.name.setVisibility(View.GONE);
holder.image.setVisibility(View.GONE);
}
else {
holder.header.setVisibility(View.GONE);
holder.name.setVisibility(View.VISIBLE);
holder.image.setVisibility(View.VISIBLE);
SharedPreferences prefs=activity.getSharedPreferences("myNumber",0);
final String myNumber=prefs.getString("number","not pund");
holder.name.setText(contacts.get(position).contact.name);
if(contacts.get(position).contact.isRegistered.equalsIgnoreCase("true")){
holder.image.setBackgroundResource(R.drawable.contact_offline_pic);
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(activity, ChatRoomActivity.class);
AppMasterManager.activity=ChatRoomActivity.class;
intent.putExtra("room",contacts.get(position).contact.room);
intent.putExtra("contact_name",contacts.get(position).contact.name);
intent.putExtra("myNumber",myNumber);
if (contacts.get(position).contact.isPrivate.equalsIgnoreCase("true")){
if (!DatabaseHandler.getDataBaseHandler(activity).numberExist(contacts.get(position).contact.phone_number)){
DatabaseHandler.getDataBaseHandler(activity).addPrivateContact(contacts.get(position).contact);
try {
ChatService.bind.getService().joinANumber(contacts.get(position).contact);
} catch (JSONException e) {
e.printStackTrace();
}
}
intent.putExtra("account", Accounts.SECONDARY_ACCOUNT);
}else {
intent.putExtra("account", Accounts.PRIMARY_ACCOUNT);
}
Log.wtf("from grid adapter inflater",contacts.get(position).contact.room);
activity.startActivity(intent);
}
});
if(contacts.get(position).contact.state.equalsIgnoreCase("offline")){
holder.image.setBackgroundResource(R.drawable.contact_offline_pic);
}
else {
holder.image.setBackgroundResource(R.drawable.contact_online_pic);
}
}
else {
holder.image.setBackgroundResource(R.drawable.contact_unregistered_pic);
}
}
}
#Override
public int getItemCount() {
return contacts.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView header;
public TextView name;
public ImageView image;
public ViewHolder(View itemView) {
super(itemView);
header=(TextView)itemView.findViewById(R.id.first_char_header);
name=(TextView)itemView.findViewById(R.id.contact_name);
image=(ImageView)itemView.findViewById(R.id.image_grid_contact);
}
}
#Override
public int getItemViewType(int position) {
if(contacts.get(position).type==0){
return 4;
}
else {
return 1;
}
}
public void search(String pattern){
searchedString=pattern;
if(!TextUtils.isEmpty(pattern)) {
searchedString=pattern;
gridsMap.clear();
gridsMap=DatabaseHandler.getDataBaseHandler(activity).getContactsByAlphabetsWithPattern(pattern);
contacts.clear();
loadData();
}
else {
gridsMap.clear();
gridsMap=DatabaseHandler.getDataBaseHandler(activity).getContactsByAlphabets();
contacts.clear();
loadData();
}
notifyDataSetChanged();
}
public void updateDataSet(){
if(!TextUtils.isEmpty(searchedString)){
contacts.clear();
gridsMap.clear();
gridsMap=DatabaseHandler.getDataBaseHandler(activity).getContactsByAlphabetsWithPattern(searchedString);
loadData();
notifyDataSetChanged();
}
else {
contacts.clear();
gridsMap.clear();
gridsMap=DatabaseHandler.getDataBaseHandler(activity).getContactsByAlphabets();
loadData();
notifyDataSetChanged();
}
}
void loadData(){
for(String c:gridsMap.keySet()){
contacts.add(new Item(0,c));
Log.wtf("add","+");
for(Contact d:gridsMap.get(c)){
contacts.add(new Item(1,c,d));
}}
}
public void searchOnline(final String pattern) throws JSONException {
if(!TextUtils.isEmpty(pattern)){
JSONObject object=new JSONObject();
object.put("pattern",pattern);
JsonObjectRequest request_json = new JsonObjectRequest(WebServiceApi.SEARCH_SECONDARY_CONTACTS_ONLINE,object, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
if(response.getJSONArray("res").length()>0){
contacts.clear();
Log.w("result ",response.getJSONArray("res").getJSONObject(0).getJSONObject("secondary_account").getString("user_name").toString());
contacts.add(new Item(0,pattern.toCharArray()[0]+""));
for(int i=0;i<response.getJSONArray("res").length();i++){
String name=response.getJSONArray("res").getJSONObject(i).getJSONObject("secondary_account").getString("user_name");
String phone_number=response.getJSONArray("res").getJSONObject(i).getString("phone_number");
String room;
if(phone_number.compareTo(myNumber)>0){
room=phone_number+myNumber;
}
else {
room=myNumber+phone_number;
}
Contact contact=new Contact();
contact.name=name;
contact.room=room;
contact.phone_number=phone_number;
contact.isRegistered="true";
contact.state="offline";
contact.isPrivate="true";
contacts.add(new Item(1,pattern.toCharArray()[0]+"",contact));
}
notifyDataSetChanged();
}
else{
contacts.clear();
loadData();
notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("No Activity", error.getMessage());
}
});
AppController.getInstance().addToRequestQueue(request_json);
}
else {
contacts.clear();
loadData();
notifyDataSetChanged();
}
}
public void setNumber(String number){
myNumber=number;
}
}
ContactsFragement:
public class ContactsFragment 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 OnContactsFragementInteraction mListener;
private RecyclerView listContacts;
private GridLayoutManager manager;
private HashMap<String,Contact> roomMaps;
private String number;
private boolean isLoaded=false;
private RecyclerGridLayoutAdapter adapter;
public ContactsFragment() {
}
/**
* 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 ContactsFragment.
*/
// TODO: Rename and change types and number of parameters
public static ContactsFragment newInstance(String param1, String param2) {
ContactsFragment fragment = new ContactsFragment();
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);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_contacts, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListener.pressed();
if(savedInstanceState==null){Toast.makeText(getActivity(),"First Time running this fragment",Toast.LENGTH_SHORT).show();}
roomMaps = new HashMap<>();
listContacts = (RecyclerView) getActivity().findViewById(R.id.list_contacts);
EditText contact_search_box = (EditText) getActivity().findViewById(R.id.search_box_contacts);
contact_search_box.clearFocus();
number = this.getArguments().getString("number");
// contactsListAdapter = new ContactsListAdapterAlternative(getActivity(), new ArrayList<GridLayoutAdapter>(), R.layout.list_contacts_item);
// listContacts.setAdapter(contactsListAdapter);
manager=new GridLayoutManager(getActivity(),4);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return (adapter.getItemViewType(position));
}
});
adapter=new RecyclerGridLayoutAdapter(R.layout.list_contacts_item,new ArrayList<Item>(),getActivity());
adapter.setNumber(number);
manager.setOrientation(LinearLayoutManager.VERTICAL);
listContacts.setLayoutManager(manager);
listContacts.setHasFixedSize(true);
listContacts.setAdapter(adapter);
EditText search_online_box=getActivity().findViewById(R.id.search_online);
search_online_box.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
adapter.searchOnline(s.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
contact_search_box.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
adapter.search(charSequence.toString());
}
#Override
public void afterTextChanged(Editable editable) {
}
});
isLoaded=true;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnContactsFragementInteraction) {
mListener = (OnContactsFragementInteraction) context;
mListener.pressed();
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
public void updateState(String room,HashMap<String,String> map) {
if(adapter!=null)
adapter.updateDataSet();
}
#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 OnContactsFragementInteraction {
// TODO: Update argument type and name
void pressed();
ChatService getService();
void setRoutablity(boolean routablity);
}
}
fragment_contacts:
<RelativeLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/contactsFragment"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:id="#+id/topSearchBar"
android:weightSum="2">
<EditText
android:id="#+id/search_box_contacts"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="10dp"
android:textSize="15sp"
android:hint="search contacts"
android:background="#beddeb"/>
<EditText
android:id="#+id/search_online"
android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="search online"
android:padding="10dp"
android:textSize="15sp"
android:background="#5fc0e9"
android:layout_weight="1"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/list_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/topSearchBar"
android:scrollbars="vertical"
tools:listitem="#layout/list_contacts_item">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
list_contact_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/first_char_header"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="a"
android:paddingTop="6dp"
android:paddingLeft="8dp"
android:textSize="25sp"
android:textColor="#c1292f"
android:background="#f2f2f2"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:lines="2"
android:id="#+id/contact_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Abdallah"
android:padding="5dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:src="#drawable/contact_small"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:id="#+id/image_grid_contact"
android:background="#drawable/contact_offline_pic"/>
</LinearLayout>
</LinearLayout>
This gridView is simply a contacts grid where it shows all the contacts available and registered in my network...
On log it shows that it recognizes that there are registered contacts and even it receives a message and if I open the chats tab i see that this listview contact send a message though no contact is appearing in the recycler view...
I'm building a RecyclerView in a Fragment, which brings in data from Firebase database and suppose to show them on a CardView. I wrote all the code as shown below but all that appears upon running is an empty RecyclerView Fragment with the method getItemCount() returning always 0.
card_item.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="10dp"
android:orientation="horizontal"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary">
<TextView
android:id="#+id/primaryText"
android:layout_width="300dp"
android:layout_height="60dp"
android:textColor="#color/colorPrimary"
android:textSize="24sp" />
<TextView
android:id="#+id/subText"
android:layout_width="300dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:textColor="#color/colorPrimary"
android:textSize="14sp" />
<TextView
android:id="#+id/rateValue"
android:layout_width="300dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#+id/subText"
android:textColor="#color/colorPrimary"
android:textSize="24sp" />
</RelativeLayout>
fragment_profile.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F1F1F1"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/placesRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
PlacesModel.java
public class PlaceModel {
private String mPrimaryText, mSubText, mRateValue;
public PlaceModel() {
}
public PlaceModel(String mCardImage, String mPrimaryText,
String mSubText, String mRateValue) {
//this.mCardImageURL = mCardImage;
this.mPrimaryText = mPrimaryText;
this.mSubText = mSubText;
this.mRateValue = mRateValue;
}
public void setmPrimaryText(String mPrimaryText) {
this.mPrimaryText = mPrimaryText;
}
public void setmSubText(String mSubText) {
this.mSubText = mSubText;
}
public void setmRateValue(String mRateValue) {
this.mRateValue = mRateValue;
}
public String getmPrimaryText() {
return mPrimaryText;
}
public String getmSubText() {
return mSubText;
}
public String getmRateValue() {
return mRateValue;
}}
PlacesAdapter.java
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.PlacesViewHolder> {
private ArrayList<PlaceModel> cardContents;
private Context context;
public PlacesAdapter(Context context, ArrayList<PlaceModel> cardContents) {
this.cardContents = cardContents;
this.context = context;
}
#Override
public PlacesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.card_item, parent, false);
return new PlacesViewHolder(view);
}
#Override
public void onBindViewHolder(PlacesViewHolder holder, int position) {
PlaceModel place = cardContents.get(position);
holder.primaryText.setText(place.getmPrimaryText());
holder.subText.setText(place.getmSubText());
holder.rateValue.setText(place.getmRateValue());
}
#Override
public int getItemCount() {
return cardContents.size();
}
public class PlacesViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
public TextView primaryText, subText, rateValue;
public PlacesViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.cardView);
primaryText = (TextView) itemView.findViewById(R.id.primaryText);
subText = (TextView) itemView.findViewById(R.id.subText);
rateValue = (TextView) itemView.findViewById(R.id.rateValue);
}
}}
FirebaseConnector.java
public class FirebaseConnector {
DatabaseReference db;
PlaceModel placeModel = new PlaceModel();
ArrayList<PlaceModel> cardContent = new ArrayList<>();
public FirebaseConnector(DatabaseReference db) {
this.db = db;
}
public ArrayList<PlaceModel> retrieve() {
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return cardContent;
}
private void fetchData(DataSnapshot dataSnapshot) {
cardContent.clear(); //clear card content from last usage
for (DataSnapshot ds : dataSnapshot.getChildren()) {
placeModel = ds.child("Place Model").getValue(PlaceModel.class);
cardContent.add(placeModel);
}
}}
ProfileFragment.java
public class ProfileFragment 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";
/////////////////////////////////////////////////////////////
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private RecyclerView placesRecycler;
private PlacesAdapter placesAdapter;
private FirebaseConnector connector;
private DatabaseReference ref;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public ProfileFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static ProfileFragment newInstance(String param1, String param2) {
ProfileFragment fragment = new ProfileFragment();
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);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_profile, container, false);
mAuth = FirebaseAuth.getInstance();
//Initialize Database..
ref = FirebaseDatabase.getInstance().getReference();
connector = new FirebaseConnector(ref);
//Initialize RecyclerView
placesRecycler = (RecyclerView)v.findViewById(R.id.placesRecycler);
placesRecycler.setLayoutManager(new LinearLayoutManager(this.getActivity()));
//Adapter
placesAdapter = new PlacesAdapter(this.getActivity(), connector.retrieve());
placesRecycler.setAdapter(placesAdapter);
Toast.makeText(getActivity(), "We have "+placesAdapter.getItemCount()+" cards", Toast.LENGTH_LONG).show();
return v;
}
#Override
public void onStart() {
super.onStart();
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
}
}
public void updateUI() {
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
}
}}
Database trial structure
Database trial structure
I see that retrieve method will return empty array list because it won't wait for the listener to finish (note that listener works in another thread)
You may make move the listener to the profile fragment and every time you update the ArrayList write
placesRecycler.notifydatasetchanged();
Recyclerview doesnt call any Adapter method :onBindViewHolder,onCreateViewHolder therefor the adapter is empty
here is my code :
public class PostsFragment extends Fragment {
public static final String TAG = "PostsFragment";
private static final String KEY_LAYOUT_POSITION = "layoutPosition";
private static final String KEY_TYPE = "type";
public static final int TYPE_HOME = 1001;
public static final int TYPE_FEED = 1002;
private int mRecyclerViewPosition = 0;
private OnPostSelectedListener mListener;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter<PostViewHolder> mAdapter;
public PostsFragment() {
// Required empty public constructor
}
public static PostsFragment newInstance(int type) {
PostsFragment fragment = new PostsFragment();
Bundle args = new Bundle();
args.putInt(KEY_TYPE, type);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_posts, container, false);
rootView.setTag(TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
if (savedInstanceState != null) {
// Restore saved layout manager type.
mRecyclerViewPosition = (int) savedInstanceState
.getSerializable(KEY_LAYOUT_POSITION);
mRecyclerView.scrollToPosition(mRecyclerViewPosition);
// TODO: RecyclerView only restores position properly for some tabs.
}
switch (getArguments().getInt(KEY_TYPE)) {
case TYPE_HOME:
Log.d(TAG, "Restoring recycler view position (following): " + mRecyclerViewPosition);
FirebaseUtil.getCurrentUserRef().child("following").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(final DataSnapshot followedUserSnapshot, String s) {
String followedUserId = followedUserSnapshot.getKey();
String lastKey = "";
if (followedUserSnapshot.getValue() instanceof String) {
lastKey = followedUserSnapshot.getValue().toString();
}
Log.d(TAG, "followed user id: " + followedUserId);
Log.d(TAG, "last key: " + lastKey);
FirebaseUtil.getPeopleRef().child(followedUserId).child("posts")
.orderByKey().startAt(lastKey).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(final DataSnapshot postSnapshot, String s) {
HashMap<String, Object> addedPost = new HashMap<String, Object>();
addedPost.put(postSnapshot.getKey(), true);
FirebaseUtil.getFeedRef().child(FirebaseUtil.getCurrentUserId())
.updateChildren(addedPost).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
FirebaseUtil.getCurrentUserRef().child("following")
.child(followedUserSnapshot.getKey())
.setValue(postSnapshot.getKey());
}
});
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
FirebaseUtil.getFeedRef().child(FirebaseUtil.getCurrentUserId())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final List<String> postPaths = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Log.d(TAG, "adding post key: " + snapshot.getKey());
postPaths.add(snapshot.getKey());
}
mAdapter = new FirebasePostQueryAdapter(postPaths,
new FirebasePostQueryAdapter.OnSetupViewListener() {
#Override
public void onSetupView(PostViewHolder holder, Post post, int position, String postKey) {
setupPost(holder, post, position, postKey);
}
});
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
break;
default:
throw new RuntimeException("Illegal post fragment type specified.");
}
mRecyclerView.setAdapter(mAdapter);
}
private FirebaseRecyclerAdapter<Post, PostViewHolder> getFirebaseRecyclerAdapter(Query query) {
return new FirebaseRecyclerAdapter<Post, PostViewHolder>(
Post.class, R.layout.post_item, PostViewHolder.class, query) {
#Override
public void populateViewHolder(final PostViewHolder postViewHolder,
final Post post, final int position) {
setupPost(postViewHolder, post, position, null);
}
#Override
public void onViewRecycled(PostViewHolder holder) {
super.onViewRecycled(holder);
}
};
}
private void setupPost(final PostViewHolder postViewHolder, final Post post, final int position, final String inPostKey) {
postViewHolder.setPhoto(post.getThumb_url());
postViewHolder.setText(post.getText());
postViewHolder.setTimestamp(DateUtils.getRelativeTimeSpanString(
(long) post.getTimestamp()).toString());
final String postKey;
if (mAdapter instanceof FirebaseRecyclerAdapter) {
postKey = ((FirebaseRecyclerAdapter) mAdapter).getRef(position).getKey();
} else {
postKey = inPostKey;
}
Author author = post.getAuthor();
postViewHolder.setAuthor(author.getFull_name(), author.getUid());
postViewHolder.setIcon(author.getProfile_picture(), author.getUid());
ValueEventListener likeListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
postViewHolder.setNumLikes(dataSnapshot.getChildrenCount());
if (dataSnapshot.hasChild(FirebaseUtil.getCurrentUserId())) {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.LIKED, getActivity());
} else {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.NOT_LIKED, getActivity());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
FirebaseUtil.getLikesRef().child(postKey).addValueEventListener(likeListener);
postViewHolder.mLikeListener = likeListener;
postViewHolder.setPostClickListener(new PostViewHolder.PostClickListener() {
#Override
public void showComments() {
Log.d(TAG, "Comment position: " + position);
mListener.onPostComment(postKey);
}
#Override
public void toggleLike() {
Log.d(TAG, "Like position: " + position);
mListener.onPostLike(postKey);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null && mAdapter instanceof FirebaseRecyclerAdapter) {
((FirebaseRecyclerAdapter) mAdapter).cleanup();
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save currently selected layout manager.
int recyclerViewScrollPosition = getRecyclerViewScrollPosition();
Log.d(TAG, "Recycler view scroll position: " + recyclerViewScrollPosition);
savedInstanceState.putSerializable(KEY_LAYOUT_POSITION, recyclerViewScrollPosition);
super.onSaveInstanceState(savedInstanceState);
}
private int getRecyclerViewScrollPosition() {
int scrollPosition = 0;
// TODO: Is null check necessary?
if (mRecyclerView != null && mRecyclerView.getLayoutManager() != null) {
scrollPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager())
.findFirstCompletelyVisibleItemPosition();
}
return scrollPosition;
}
/**
* 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/>
*/
public interface OnPostSelectedListener {
void onPostComment(String postKey);
void onPostLike(String postKey);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnPostSelectedListener) {
mListener = (OnPostSelectedListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnPostSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
the adapter class
public class FirebasePostQueryAdapter extends RecyclerView.Adapter<PostViewHolder> {
private final String TAG = "PostQueryAdapter";
private List<String> mPostPaths;
private OnSetupViewListener mOnSetupViewListener;
public FirebasePostQueryAdapter(List<String> paths, OnSetupViewListener onSetupViewListener) {
if (paths == null || paths.isEmpty()) {
mPostPaths = new ArrayList<>();
} else {
mPostPaths = paths;
}
mOnSetupViewListener = onSetupViewListener;
}
#Override
public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.post_item, parent, false);
return new PostViewHolder(v);
}
public void setPaths(List<String> postPaths) {
mPostPaths = postPaths;
notifyDataSetChanged();
}
public void addItem(String path) {
mPostPaths.add(path);
notifyItemInserted(mPostPaths.size());
}
#Override
public void onBindViewHolder(final PostViewHolder holder, int position) {
DatabaseReference ref = FirebaseUtil.getPostsRef().child(mPostPaths.get(position));
// TODO: Fix this so async event won't bind the wrong view post recycle.
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
Log.d(TAG, "post key: " + dataSnapshot.getKey());
mOnSetupViewListener.onSetupView(holder, post, holder.getAdapterPosition(),
dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError firebaseError) {
Log.e(TAG, "Error occurred: " + firebaseError.getMessage());
}
};
ref.addValueEventListener(postListener);
holder.mPostRef = ref;
holder.mPostListener = postListener;
}
#Override
public void onViewRecycled(PostViewHolder holder) {
super.onViewRecycled(holder);
holder.mPostRef.removeEventListener(holder.mPostListener);
}
#Override
public int getItemCount() {
return mPostPaths.size();
}
public interface OnSetupViewListener {
void onSetupView(PostViewHolder holder, Post post, int position, String postKey);
}
}
the main class
public class FeedsActivity extends AppCompatActivity implements PostsFragment.OnPostSelectedListener {
private static final String TAG = "FeedsActivity";
private FloatingActionButton mFab;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_feeds);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ViewPager viewPager = (ViewPager) findViewById(R.id.feeds_view_pager);
FeedsPagerAdapter adapter = new FeedsPagerAdapter(getSupportFragmentManager());
adapter.addFragment(PostsFragment.newInstance(PostsFragment.TYPE_HOME), "HOME");
adapter.addFragment(PostsFragment.newInstance(PostsFragment.TYPE_FEED), "FEED");
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(1);
TabLayout tabLayout = (TabLayout) findViewById(R.id.feeds_tab_layout);
tabLayout.setupWithViewPager(viewPager);
mFab = (FloatingActionButton) findViewById(R.id.fab);
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null || user.isAnonymous()) {
Toast.makeText(FeedsActivity.this, "You must sign-in to post.", Toast.LENGTH_SHORT).show();
return;
}
Intent newPostIntent = new Intent(FeedsActivity.this, NewPostActivity.class);
startActivity(newPostIntent);
}
});
}
#Override
public void onPostComment(String postKey) {
Intent intent = new Intent(this, CommentsActivity.class);
intent.putExtra(CommentsActivity.POST_KEY_EXTRA, postKey);
startActivity(intent);
}
#Override
public void onPostLike(final String postKey) {
final String userKey = FirebaseUtil.getCurrentUserId();
final DatabaseReference postLikesRef = FirebaseUtil.getLikesRef();
postLikesRef.child(postKey).child(userKey).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// User already liked this post, so we toggle like off.
postLikesRef.child(postKey).child(userKey).removeValue();
} else {
postLikesRef.child(postKey).child(userKey).setValue(ServerValue.TIMESTAMP);
}
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_feeds, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
// TODO: Add settings screen.
return true;
} else if (id == R.id.action_profile) {
startActivity(new Intent(this, ProfileActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
class FeedsPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public FeedsPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
activity_feeds.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.TabLayout
android:id="#+id/feeds_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/feeds_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_input_add"
android:tint="#android:color/white"/>
post_item.xml
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_margin="8dp"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:padding="10dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/post_author_icon"
android:layout_width="#dimen/post_author_icon_size"
android:layout_height="#dimen/post_author_icon_size"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:id="#+id/post_author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#id/post_author_icon"
android:layout_marginLeft="4dp"
style="#style/Base.TextAppearance.AppCompat.Title"
android:textColor="#android:color/primary_text_light_nodisable"
android:text="Unknown"/>
<TextView
android:id="#+id/post_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:textColor="#android:color/primary_text_light"
android:textSize="18sp" />
</RelativeLayout>
<ImageView
android:id="#+id/post_photo"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop" />
<TextView
android:id="#+id/post_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="false"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textColor="#android:color/primary_text_light"
android:textSize="16sp"
android:ellipsize="end" />
<TextView
android:id="#+id/post_num_likes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:textColor="#android:color/secondary_text_light"
android:textSize="14sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp">
<ImageView
android:id="#+id/post_like_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/heart_full"/>
<ImageView
android:id="#+id/post_comment_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="6dp"
android:layout_toRightOf="#id/post_like_icon"
android:src="#drawable/ic_chat_24dp"
android:tint="#color/blue_grey_500"/>
</RelativeLayout>
</LinearLayout>
fragment_posts.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PostsFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
You are setting the adapter on the recyclerview before the adapter has been initialised. Try:
mAdapter = new FirebasePostQueryAdapter(postPaths,
new FirebasePostQueryAdapter.OnSetupViewListener() {
#Override
public void onSetupView(PostViewHolder holder, Post post, int position, String postKey) {
setupPost(holder, post, position, postKey);
}
});
mRecyclerView.setAdapter(mAdapter);
In my application, I have a ListView in a DialogFragment which displays CheckedTextViews. I am using the AppCompat library to integrate Material Design. I set the "android:checkMark" as "?android:attr/listChoiceIndicatorMultiple". It shows the unchecked state perfectly fine and it applies the correct tint. However, when I check the item, a check mark does not show. This is an image of the problem.
Imgur
As you can see, it tints the CheckedTextView properly, but it does not show a check mark. I am stumped about fixing this. Did anyone else encounter this problem? If so, do you have a solution?
The following is my XML:
item_add_to_queue.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/single_line_height">
<CheckedTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:gravity="center_vertical"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:ellipsize="middle"
android:singleLine="true"
android:textColor="#color/secondaryText"
android:textSize="#dimen/typography_subhead"
android:id="#+id/checkedTextView"/>
</RelativeLayout>
fragment_add_to_queue.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/dialog_content_padding"
android:background="#color/secondaryBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/baseline_component_unit"
android:textColor="#color/primaryBlue500"
android:textSize="#dimen/typography_title"
android:textStyle="bold"
android:text="#string/dialog_add_to_queue" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<include layout="#layout/empty"/>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:headerDividersEnabled="false"
android:footerDividersEnabled="false"
android:choiceMode="multipleChoice"
android:listSelector="#drawable/item_selector"
android:id="#+id/listView"/>
</FrameLayout>
</LinearLayout>
This is my code for the DialogFragment:
AddToQueueFragment.java
public class AddToQueueFragment extends DialogFragment implements AddToQueueView, AddToQueueMapper {
public static final String TAG = AddToQueueFragment.class.getSimpleName();
public static final String REQUEST_ARGUMENT_KEY = TAG + ":" + "RequestArgumentKey";
private AddToQueuePresenter mAddToQueuePresenter;
private ListView mListView;
private RelativeLayout mEmptyRelativeLayout;
private Button mToggleButton;
public static AddToQueueFragment newInstance(RequestWrapper mangaRequest) {
AddToQueueFragment newInstance = new AddToQueueFragment();
Bundle arguments = new Bundle();
arguments.putParcelable(REQUEST_ARGUMENT_KEY, mangaRequest);
newInstance.setArguments(arguments);
return newInstance;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAddToQueuePresenter = new AddToQueuePresenterImpl(this, this);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View addToQueueView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_add_to_queue, null);
mListView = (ListView)addToQueueView.findViewById(R.id.listView);
mEmptyRelativeLayout = (RelativeLayout)addToQueueView.findViewById(R.id.emptyRelativeLayout);
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
dialogBuilder.setView(addToQueueView)
.setPositiveButton(R.string.add_to_queue_dialog_button_queue, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mAddToQueuePresenter.onQueueButtonClick();
}
})
.setNeutralButton(R.string.add_to_queue_dialog_button_toggle_all, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Do Nothing.
}
})
.setNegativeButton(R.string.catalogue_filter_dialog_button_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
AddToQueueFragment.this.getDialog().cancel();
}
});
return dialogBuilder.create();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
mAddToQueuePresenter.restoreState(savedInstanceState);
} else {
mAddToQueuePresenter.handleInitialArguments(getArguments());
}
mAddToQueuePresenter.initializeViews();
mAddToQueuePresenter.initializeDataFromDatabase();
}
#Override
public void onStart() {
super.onStart();
mAddToQueuePresenter.overrideDialogButtons();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mAddToQueuePresenter.saveState(outState);
}
#Override
public void onDestroy() {
super.onDestroy();
mAddToQueuePresenter.destroyAllSubscriptions();
mAddToQueuePresenter.releaseAllResources();
}
// AddToQueueView:
#Override
public void initializeEmptyRelativeLayout() {
if (mEmptyRelativeLayout != null) {
((ImageView) mEmptyRelativeLayout.findViewById(R.id.emptyImageView)).setImageResource(R.drawable.ic_file_download_white_48dp);
((ImageView) mEmptyRelativeLayout.findViewById(R.id.emptyImageView)).setColorFilter(getResources().getColor(R.color.accentPinkA200), PorterDuff.Mode.MULTIPLY);
((TextView) mEmptyRelativeLayout.findViewById(R.id.emptyTextView)).setText(R.string.no_available_downloads);
((TextView) mEmptyRelativeLayout.findViewById(R.id.instructionsTextView)).setText(R.string.available_downloads_instructions);
}
}
#Override
public void hideEmptyRelativeLayout() {
if (mEmptyRelativeLayout != null) {
mEmptyRelativeLayout.setVisibility(View.GONE);
}
}
#Override
public void showEmptyRelativeLayout() {
if (mEmptyRelativeLayout != null) {
mEmptyRelativeLayout.setVisibility(View.VISIBLE);
}
}
#Override
public void overrideToggleButton() {
AlertDialog currentDialog = (AlertDialog)getDialog();
if (currentDialog != null) {
mToggleButton = currentDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
mToggleButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mAddToQueuePresenter.onToggleButtonClick();
}
});
}
}
#Override
public void selectAll() {
if (mListView != null) {
for (int index = 0; index < mListView.getCount(); index++) {
mListView.setItemChecked(index, true);
}
}
}
#Override
public void clear() {
if (mListView != null) {
for (int index = 0; index < mListView.getCount(); index++) {
mListView.setItemChecked(index, false);
}
}
}
#Override
public Context getContext() {
return getActivity();
}
// AddToQueueMapper:
#Override
public void registerAdapter(BaseAdapter adapter) {
if (mListView != null) {
mListView.setAdapter(adapter);
}
}
#Override
public int getCheckedItemCount() {
if (mListView != null) {
return mListView.getCheckedItemCount();
} else {
return 0;
}
}
#Override
public SparseBooleanArray getCheckedItemPositions() {
if (mListView != null) {
return mListView.getCheckedItemPositions();
} else {
return null;
}
}
#Override
public Parcelable getPositionState() {
if (mListView != null) {
return mListView.onSaveInstanceState();
} else {
return null;
}
}
#Override
public void setPositionState(Parcelable state) {
if (mListView != null) {
mListView.onRestoreInstanceState(state);
}
}
}
I solved the problem. The RelativeLayout should be removed such that the CheckedTextView is the only element because the ListView calls setChecked() for a View which implements the Checkable interface.
I am currently using normal horizontal navigation in my code such that when you click on the button, it will navigate to a new fragment horizontally. I want to make it such that instead of calling a new fragment it just expands /collapses upon clicking/clicking again. The code I have so far is :
Here is the activity:
public class ManageNewsCategoriesActivity extends AbsBaseDoubleButtonActivity {
private List<AdapterRow> mBreakingViews;
public HashSet<CategoryCheckableRow> mCategoriesMap = new HashSet<CategoryCheckableRow>();
private int mTitleId = R.string.title_manage;
public static void newInstance(final Activity activity) {
final Intent intent = new Intent(activity.getApplicationContext(), ManageNewsCategoriesActivity.class);
activity.startActivity(intent);
}
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_news_categories);
overridePendingTransition(R.anim.slide_in_from_bottom, R.anim.no_animation);
mActiveFragment = ManageNewsCategoriesFragment.newInstance(getSupportFragmentManager(), 0);
}
public void animateTitle(final int textViewId) {
animateTitle(textViewId, R.anim.slide_in_from_right);
}
public void animateTitle(final int textViewId, final int animationId) {
final TextView titleView = (TextView) findViewById(textViewId);
final Animation animation = AnimationUtils.loadAnimation(this, animationId);
titleView.startAnimation(animation);
}
public void setBreakingViews(final List<AdapterRow> categoryRows) {
mBreakingViews = categoryRows;
}
public List<CategoryCheckableRow> getBreakingViews() {
return removeHeaders(mBreakingViews);
}
public List<AdapterRow> getBreakingViewsCategoryRows() {
if (mBreakingViews == null) {
return null;
}
return AbsBaseManageNewsFragment.getAClone(mBreakingViews);
}
private List<CategoryCheckableRow> removeHeaders(final List<AdapterRow> mCategoryRows) {
final List<CategoryCheckableRow> items = new ArrayList<CategoryCheckableRow>();
if (mCategoryRows != null) {
for (final AdapterRow row : mCategoryRows) {
if (row instanceof CategoryCheckableRow) {
final CategoryCheckableRow item = (CategoryCheckableRow) row;
items.add(item);
}
}
}
return items;
}
public boolean isDoneButtonEnabled() {
return !mCategoriesMap.isEmpty();
}
public void updateCategoriesMap(final HashSet<CategoryCheckableRow> categoryRows) {
for (final CategoryCheckableRow row : categoryRows) {
if (!mCategoriesMap.add(row)) {
mCategoriesMap.remove(row);
}
}
}
#Override
protected int getTitleId() {
return mTitleId;
}
#Override
public void updateTitleId(final int titleId) {
mTitleId = titleId;
updateTitleId();
}
Here is the fragment:
public class ManageNewsCategoriesFragment extends Fragment implements OnClickListener,OnCheckedChangeListener {
public final static String TAG_MANAGE_NEWS_CATEGORIES_FRAGMENT = "ManageNewsCategoriesFragment";
public static final String TYPE = "Type";
public static final String BREAKINGVIEWS = "Breakingviews";
public static final String ANIMATION = "animation";
protected Button mPreferencesDoneButton;
public static ManageNewsCategoriesFragment newInstance(final FragmentManager manager, final int animation) {
final ManageNewsCategoriesFragment fragment = new ManageNewsCategoriesFragment();
final Bundle arguments = new Bundle();
arguments.putInt(ANIMATION, animation);
fragment.setArguments(arguments);
final FragmentInfo fragmentInfo = new FragmentInfo(TransactionMethods.ADD, R.id.manage_news_categories_container);
fragmentInfo.setFragmentTag(TAG_MANAGE_NEWS_CATEGORIES_FRAGMENT);
FragmentStackManager.getInstance().transitionFragment(manager, fragment, fragmentInfo);
return fragment;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_manage_news_categories, container, false);
final Bundle arguments = getArguments();
final int animation = arguments.getInt(ANIMATION, 0);
final ManageNewsCategoriesActivity activity = (ManageNewsCategoriesActivity) getActivity();
if (animation != 0) {
activity.animateTitle(R.id.actionbar_title, arguments.getInt(ANIMATION, 0));
}
return view;
}
protected void setupClickListeners() {
mPreferencesDoneButton = (Button) getActivity().findViewById(R.id.button_done);
Typeface face = Typeface.createFromAsset(mPreferencesDoneButton.getContext().getAssets(),
"fonts/proxima-nova-regular.ttf");
mPreferencesDoneButton.setTypeface(face);
mPreferencesDoneButton.setOnClickListener(this);
mPreferencesDoneButton.setEnabled(((ManageNewsCategoriesActivity) getActivity()).isDoneButtonEnabled());
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final TextView titleView = (TextView) getActivity().findViewById(R.id.actionbar_title);
titleView.setText(R.string.title_manage);
initManageNewsCategoriesFragment();
}
private void initManageNewsCategoriesFragment() {
setupClickListeners();
final Button breakingViewsButton = (Button) getView().findViewById(R.id.button_breakingviews);
breakingViewsButton.setOnClickListener(this);
}
#Override
public void onClick(final View view) {
final ManageNewsCategoriesActivity activity = (ManageNewsCategoriesActivity) getActivity();
switch (view.getId()) {
case R.id.button_breakingviews:
ManageBreakingViewsFragment.newInstance(getFragmentManager());
return;
case R.id.button_done:
syncNewsCategories(activity);
break;
default:
break;
}
activity.onBackPressed();
}
private void syncNewsCategories(final ManageNewsCategoriesActivity activity) {
final List<CategoryCheckableRow> breakingViews = activity.getBreakingViews();
if ( ArrayUtils.isNotEmpty(breakingViews)) {
RestService.start(activity, new UserCategoriesSyncOperation(NewsContentProvider.USER_CATEGORIES_URI, breakingViews));
}
}
}
Here is the corresponding xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/altercolor2" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/altercolor2"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="#+id/button_breakingviews"
android:layout_width="match_parent"
android:layout_height="#dimen/manage_news_btn_ht"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:background="#drawable/manage_market_category_btnbg"
android:gravity="left|center_vertical"
android:paddingLeft="#dimen/frequent_padding_left"
android:text="#string/button_breakingviews"
android:textColor="#cccccc"
android:textSize="#dimen/title" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingRight="17.5dp"
android:paddingTop="0dp"
android:src="#drawable/arrow_chevron_selector" />
</RelativeLayout>
</LinearLayout>
</FrameLayout>
Any clue how to go about the same? Please explain programmatically and with respect to my code to avoid confusion.
Thanks!
I think what you want is a custom expandable list view. Here is a very good tutorial on it: ExpandableListView