The RecyclerView is showing all data, but the item click is not working. Here I am attaching what I have done so far. For better understanding I am removing all the unnecessary code.
This is my recyclerview item xml.
<data>
<variable
name="model"
type="com.xyz.abc.pojo.EmployeeListWithDesignationSetGet" />
<variable
name="viewModel"
type="com.xyz.abc.viewmodels.EmpListWithDesigViewModel" />
</data>
<LinearLayout
android:id="#+id/ll_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:clickable="true"
android:focusable="true"
android:onClick="#{() -> viewModel.itemClick(model)}">
<TextView
android:id="#+id/tv_show_details"
android:layout_width="70dp"
android:layout_height="30dp"
android:text="Show"
android:textColor="#FFFFFF" />
</LinearLayout>
The ViewModel class where I have written the click method.
public class EmpListWithDesigViewModel extends ViewModel {
private MutableLiveData<List<EmployeeListWithDesignationSetGet>> mutableLiveData;
private EmpListWithDesigClickListener listener;
private EmpListWithDesigRepository empListWithDesigRepository;
public void setListener(EmpListWithDesigClickListener listener) {
this.listener = listener;
}
public void init() {
if (mutableLiveData != null) {
return;
}
empListWithDesigRepository = EmpListWithDesigRepository.getInstance();
mutableLiveData = empListWithDesigRepository.getEmpList();
}
public MutableLiveData<List<EmployeeListWithDesignationSetGet>> getEmpList() {
return mutableLiveData;
}
public void itemClick(EmployeeListWithDesignationSetGet employeeListWithDesignationSetGet) {
listener.onItemClick(employeeListWithDesignationSetGet);
}
}
Now in activity I am implementing the click interface.
public class EmployeeDesignationActivity extends AppCompatActivity implements EmpListWithDesigClickListener {
private RecyclerView mRv_recyclerView;
private List<EmployeeListWithDesignationSetGet> arrayList;
private EmployeeListWithDesigAdapter employeeListWithDesigAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_employee_designation);
setViewReferences();
arrayList = new ArrayList<>();
employeeListWithDesigAdapter = new EmployeeListWithDesigAdapter(this,arrayList);
mRv_recyclerView.setAdapter(employeeListWithDesigAdapter);
EmpListWithDesigViewModel empListWithDesigViewModel = new ViewModelProvider(this,new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(EmpListWithDesigViewModel.class);
empListWithDesigViewModel.setListener(this);
empListWithDesigViewModel.init();
empListWithDesigViewModel.getEmpList().observe(this, new Observer<List<EmployeeListWithDesignationSetGet>>() {
#Override
public void onChanged(List<EmployeeListWithDesignationSetGet> employeeListWithDesignationSetGets) {
arrayList.addAll(employeeListWithDesignationSetGets);
employeeListWithDesigAdapter.notifyDataSetChanged();
}
});
}
private void setViewReferences(){
mRv_recyclerView = findViewById(R.id.rv_activity_employee_designation);
}
#Override
public void onItemClick(EmployeeListWithDesignationSetGet employeeListWithDesignationSetGet) {
String phone = employeeListWithDesignationSetGet.getEmpPhone();
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone));
startActivity(intent);
}
}
Pardon me if I have not provided enough info, this is my first SO post. Thanks
You should remove the android:onClick="#{() -viewModel.itemClick(model)}" from Linearlayout. Also add the below properties.
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
Then your item layout will be as below:
<LinearLayout
android:id="#+id/ll_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
>
<TextView
android:id="#+id/tv_show_details"
android:layout_width="70dp"
android:layout_height="30dp"
android:text="Show"
android:textColor="#FFFFFF" />
</LinearLayout>
Problem fixed. I forgot to bind the viewmodel in recyclerview adapter.
Related
I am working on android studio. I am using fragments to make the app workflow. The app is basically for order taking. One customer can have more than one order. So for it, I have used RecyclerView. Below is my GUI
What do I want to do?
I want to update my Total Qty and Order Value in such a way that whenever the user enters the quantity both edittexts should be updated. For example, in the above image, I searched for one product, its rate is 287.30 and when I entered the quantity 5 then Total Qty: 5 and Order Value: 287.30. After that, I select another product and enter its quantity 8 then both edit text should be updated like Total Qty: 13 and Order Value: 509.15, and when I remove any product then it should subtract the total quantity and order value.
The Total Qty: and Order Value: is in my main fragment. Below is my code
Fragment Layout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/products"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:focusable="true" />
</LinearLayout>
<LinearLayout
android:id="#+id/product_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_product">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total Qty:" />
<EditText
android:id="#+id/total_qty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_horizontal"
android:hint=""
android:inputType="number" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Order Value :" />
<EditText
android:id="#+id/order_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_horizontal"
android:hint=""
android:inputType="none" />
</LinearLayout>
</LinearLayout>
Fragment Code
// created getter setters
public EditText totalQty,totalOrder;
public EditText getTotalQty(){
return totalQty;
}
public void setTotalQty(EditText et){
this.totalQty = et;
}
public EditText getTotalOrder(){return totalOrder;}
public void setTotalOrder(EditText ett){this.totalOrder=ett;}
addProduct.setOnClickListener(v -> {
mProducts.add(new ProductDetail());
mProductsAdapter.setProducts(mProducts);
productsRecyclerView.smoothScrollToPosition(mProducts.size() - 1);
});
Product Layout
<AutoCompleteTextView
android:id="#+id/tv_product"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:gravity="start"
android:hint="Enter Product"
android:inputType="text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/product_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_product">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_qty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="left"
android:hint="Enter Quantity"
android:inputType="number" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="left"
android:hint="Prod Price"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_specs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="left"
android:hint="Prod Specs"
android:inputType="none" />
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/btn_rmv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"
android:text="Remove Product"
android:textColor="#color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/product_infos" />
Product Adapter
View productView = inflater.inflate(R.layout.product_layout, parent, false);
ProductViewHolder viewHolder = new ProductViewHolder(productView);
viewHolder.tvProduct.setAdapter(prodAdapter);
viewHolder.tvProduct.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)
{
}
#Override
public void afterTextChanged(Editable s) {
mProductManager = new ProductManager(context);
int position = viewHolder.getAdapterPosition();
if (position != -1) {
ProductDetail productDetail = mProductManager.getProductByPrdName(s.toString());
mProducts.get(position).setProductNameFull(s.toString());
viewHolder.price.setText(productDetail.getPrice());
viewHolder.spec.setText(productDetail.getProductSpec());
viewHolder.pgrp.setText(productDetail.getProductGroup());
viewHolder.ccode.setText(productDetail.getCompanyCode());
viewHolder.cname.setText(productDetail.getCompanyName());
viewHolder.pcode.setText(productDetail.getProductCode());
}
}
});
viewHolder.quantity.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) {
}
#Override
public void afterTextChanged(Editable s) {
int position = viewHolder.getAdapterPosition();
if (position != -1) {
Integer val = null;
try {
val = Integer.valueOf(s.toString());
} catch (Exception e) {
}
mProducts.get(position).setQuantity(val);
}
}
});
viewHolder.removeBtn.setOnClickListener(v -> {
int position = viewHolder.getAdapterPosition();
if (position != -1) {
mProducts.remove(position);
notifyItemRemoved(position);
}
});
return viewHolder;
Update 1
Below is my Fragment Class
public class SurveyFormFragment extends Fragment {
.
.
.
.
private final LiveData<Integer> mQuantity = new MutableLiveData<>(0);
private final LiveData<Integer> mOrderValue = new MutableLiveData<>(0);
private ViewModel mViewModel;
private FragmentBinding mBinding;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d("myfragment", "onCreateView");
getActivity().setTitle(getString(R.string.title_new_survey));
mContext = getActivity();
if (view == null) {
view = inflater.inflate(R.layout.new_survey_form_layout, container, false);
mLinearLayout = view.findViewById(R.id.ll_prod);
this.initElements(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.initListeners(getActivity());
}
Bundle arguments = getArguments();
if (arguments != null && arguments.containsKey("booking_id")) {
isNewSurvey = false;
initSurveyData(arguments.getString("booking_id"));
this.updatingSurveyId = arguments.getString("booking_id");
}
}
Log.d("package", getActivity().getPackageName());
Log.d(TAG, Common.getCarrierName(getActivity()));
return view;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("myfragment", "onActivityCreated");
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
Log.d("myfragment", "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("myfragment", "onDestroy");
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
//save now
savedInstanceState.putString("faisal_qayyum", consumerNameEditText.getText().toString());
super.onSaveInstanceState(savedInstanceState);
Log.d("myfragment", "onSaveInstanceState saving " + consumerNameEditText.getText().toString());
}
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
//restore now
Log.d("myfragment", "onViewStateRestored");
}
.
.
.
.
}
Error
How can I add and then update the values?
Any help would be highly appreciated.
I will disappoint you by not sharing code. I will share you a simple graphic of what you need to do.
[Fragment]: displays your list of orders. When an event is triggered (user tapped something or changed something), forwards this event to a ViewModel. Also Observes for the ViewModel data state.
[ViewModel]: exposes a series of functions to listen for user events (e.g. the user tapped this order, or the user changed the quantity of this order to NN, etc.). Also offers a LiveData (or Flow) with the State and Data your Fragment needs. Maybe even talks to the repository where this data originates from (where you save your Orders in your persistent or backend).
Interactions:
When the UI modified something, you tell the viewModel: "This data changed, the order X, now has a quantity of Y".
The ViewModel will process this, update the State of the screen, and send the new data via your Livedata/Flow that the Fragment observes.
When the Fragment receives this new data, it will update the UI accordingly, as that's its most important job.
This whole thing has been greatly documented in the official Android recommended architecture guides. I suggest you start from there instead of trying to fight the framework and making your life more complicated.
implement interface between adapter and fragment like this (it is just sodu to tell how you have to implement things also you have to check it out how to implement interfaces
===============================================================
public frgment extends Fragment implements GetValueInterface{
in onCreate function{
int totalquantity;
call this after adapter initialization
adapter.registergetValueInterface(this)
}
#Override Void setQuantity(Int _gotquantity){
_gotquantity+=_gotquantity;
totalquantityedittext.setText(_gotquantity,TextView.BufferType.EDITABLE)
}
}
and in adapter class
Adapter class
{
public GetValueInterface instance;
function registergetValueInterface(GetValueInterface obj){
instance=obj;
}
//and in quantity edittext text watcher
call instance.setQuantity(quanity)
}
like this you can minus the quantity as well on removal of item
Actually it's releated with Interactions like LiveData.
But rather than write a looot of code, simply I'm passing runnable to childs for call it when somethink changed :)
For example:
class Root{
...
public void addItem(){
ItemController cont = new ItemController(() -> updateSums());
...
}
public void updateSums(){
//TODO
}
}
class ItemController{
Runnable updater;
public ItemController(Runnable updater){
this.updater = updater;
}
public void onSomethingChanged(){
updater.run();
}
}
You should work with LiveData and DataBinding
In order to do so you activate it in your build.gradle file:
android {
...
buildFeatures {
dataBinding true
}
}
Then add the following code.
Add a ViewModel class:
public class ViewModel extends AndroidViewModel
{
private final MediatorLiveData<Integer> mTotalQuantity = new MediatorLiveData<>();
private final MediatorLiveData<Integer> mTotalOrder = new MediatorLiveData<>();
private final List<LiveData<Integer>> mOrders = new ArrayList<>();
private final List<LiveData<Integer>> mQuantities = new ArrayList<>();
public ViewModel(#NonNull Application application)
{
super(application);
mTotalOrder.setValue(0);
mTotalQuantity.setValue(0);
}
public LiveData<Integer> getTotal()
{
return mTotalOrder;
}
public LiveData<Integer> getQuantity()
{
return mTotalQuantity;
}
public void attachQuantity(LiveData<Integer> quantity)
{
mQuantities.add(quantity);
mTotalQuantity.addSource(quantity, (q) -> calculateQuantities());
}
public void detachQuantity(LiveData<Integer> quantity)
{
mQuantities.remove(quantity);
mTotalQuantity.removeSource(quantity);
calculateQuantities();
}
private void calculateQuantities()
{
int total = 0;
for (LiveData<Integer> quantity : mQuantities)
{
Integer value = quantity.getValue();
if (value != null)
{
total += value;
}
}
mTotalQuantity.setValue(total);
}
public void attachTotal(LiveData<Integer> total)
{
mOrders.add(total);
mTotalOrder.addSource(total, (q) -> calculateOrders());
}
public void detachTotal(LiveData<Integer> total)
{
mOrders.remove(total);
mTotalOrder.removeSource(total);
calculateOrders();
}
private void calculateOrders()
{
int total = 0;
for (LiveData<Integer> order : mOrders)
{
Integer value = order.getValue();
if (value != null)
{
total += value;
}
}
mTotalOrder.setValue(total);
}
}
In your fragment class add the following:
private LiveData<Integer> mQuantity = new MutableLiveData<>(0);
private LiveData<Integer> mOrderValue = new MutableLiveData<>(0);
private ViewModel mViewModel;
private FragmentBinding mBinding;
#Override
public void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mViewModel = new ViewModelProvider(requireActivity()).get(ViewModel.class);
mViewModel.attachQuantity(mQuantity);
mViewModel.attachTotal(mOrderValue);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
mBinding = DataBindingUtil.setContentView(this, R.layout.fragment);
mBinding.quantity = mQuantity;
mBinding.order_value = mOrderValue;
}
#Override
public void onDestroy()
{
super.onDestroy();
mViewModel.detachQuantity(mQuantity);
mViewModel.detachTotal(mOrderValue);
}
Add this to your product layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="quantity"
type="android.arch.lifecycle.MutableLiveData<Integer>" />
<variable
name="order_value"
type="android.arch.lifecycle.MutableLiveData<Integer>" />
</data>
...
<EditText
android:id="#+id/prod_qty"
// This does the magic
android:text="#{quantity}" />
...
<EditText
android:id="#+id/prod_price"
// And this of course...
android:text="#{order_value}" />
...
</layout>
And this to your fragment layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="yourpackage.ViewModel" />
</data>
...
<EditText
android:id="#+id/total_qty"
// This does the magic
android:text="#{viewmodel.quantity}" />
...
<EditText
android:id="#+id/order_value"
// And this of course..
android:text="#{viewmodel.total}" />
...
</layout>
Note that in both classes you need to get the viewmodel from the activity, not from the fragment itself, so you share the same viewmodel for both classes:
ViewModelProvider(requireActivity()).get(ViewModel.class);
If you only get values of LiveData objects from within the UI Thread (which is the case in my code, as onChange of LiveData and binding updates are always called from the UI thread), you do not need to synchronize the lists in the ViewModel. Otherwise you need to make the whole story thread safe.
It is easy to understand that you want to take action when changing the value in a text field. So the first thing is to add a TextChangeListener or TextWatcher. Then, you have to work on the received text value to update the rest of the dependencies: Your product list or whatever it is.
Just a few basic things you need to take care of:
If you are working with fragment communication, propagate your changes by reloading in onResume of the fragment or activity. Or you can use EventBus or any other suitable mechanism.
Be sure to notify the adapter once you have changed the underlying data. I see a call to "notify**" after your code mProducts.get(position).setQuantity(val); is missing in your Product adapter. When modifying the underlying data, it is necessary to notify the adapter using "notify**" calls to update the recycler view.
The MutableLiveData error you posted above can be cleared with MutableLiveData declaration such as private final MutableLiveData mutableData = new MutableLiveData(0) in your case. You can have a function to just return LiveData as LiveData getData() { return mutableData; }
hello guys i'm back again on a question conserning my final project.
i have made a googlemap app with navigation drawer using activity( no fragment). i think you know about that. then rather than using header and menu, i have use a layout where the header should be so that i can make there a listview to display events all of this is clear.
screenshot
MapActivity :
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String TAG = "MapActivity";
DrawerLayout drawerLayout;
LinearLayout drawer_up;
FloatingActionsMenu mainfloating;
FloatingActionButton profile, evennement, historique,reglage,aidesupport;
ImageButton zoomin,zoomout,showtail,zoom_auto,showgeofence,maplayer,drawermenugroit,drawermenugauche;
ProgressDialog progressDialog;
private Dialog mDialog;
private GoogleMap map;
private Timer timer;
private int autoZoomedTimes = 0;// dėl bugo osmdroid library, zoom'inam du kartus ir paskui po refresh'o nebe, nes greičiausiai user'is bus pakeitęs zoom'ą
RelativeLayout nodata_layout;
private HashMap<Integer, Marker> deviceIdMarkers;
private HashMap<String, Device> markerIdDevices;
private HashMap<Integer, Polyline> deviceIdPolyline;
private HashMap<Integer, LatLng> deviceIdLastLatLng;
// private HashMap<Integer, Marker> deviceIdSmallMarkerInfo;
private long lastRefreshTime;
boolean isAutoZoomEnabled = true;
boolean isShowTitlesEnabled;
boolean isShowTailsEnabled = true;
boolean isShowGeofencesEnabled = true;
private String stopTime;
ImageButton map_layer_icon;
private AsyncTask downloadingAsync;
#Bind(R.id.listevent)
ListView listevent;
#Bind(R.id.clearAllEvents)
Button clearAllEvents;
#Bind(R.id.list) ListView list;
#Bind(R.id.nodata_layout) RelativeLayout nodata_layout1;
private boolean isRefreshLoced = false;
ApiInterface.GetGeofencesResult geofencesResult;
ArrayList<PolygonWithName> polygonsWithDetails = new ArrayList<>();
float previousZoomLevel = 0;
Boolean isAllFabsVisible;
RelativeLayout content_layout;
//fin de declaration a garder en tete
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(this);
setContentView(R.layout.activity_map);
//devices elements
deviceIdMarkers = new HashMap<>();
markerIdDevices = new HashMap<>();
deviceIdPolyline = new HashMap<>();
deviceIdLastLatLng = new HashMap<>();
final String api_key = (String) DataSaver.getInstance(MapActivity.this).load("api_key");
final EventsAdapter adapter = new EventsAdapter(this);
listevent.setAdapter(adapter);
//deviceIdSmallMarkerInfo = new HashMap<>();
//delaration des boutons pour le compte de floatingButton, etc...;
drawermenugroit = findViewById(R.id.drawermenudroit);
drawer_up = findViewById(R.id.drawerup);
drawermenugauche = findViewById(R.id.drawermenugauche);
drawerLayout = findViewById(R.id.drawer);
// profile = findViewById(R.id.profile);
mainfloating = findViewById(R.id.mainFloatingBtn);
evennement = findViewById(R.id.evennements);
historique = findViewById(R.id.historiques);
reglage = findViewById(R.id.reglages);
aidesupport = findViewById(R.id.aide_support);
zoomin = findViewById(R.id.zoom_in);
LinearLayout list_event = findViewById(R.id.list_event);
zoomout = findViewById(R.id.zoom_out);
showtail = findViewById(R.id.showtails);
zoom_auto = findViewById(R.id.autozoom);
listevent = (ListView) findViewById(R.id.listevent);
list = (ListView) findViewById(R.id.list);
showgeofence = findViewById(R.id.geofences);
maplayer = findViewById(R.id.map_layer);
map_layer_icon = (ImageButton) findViewById(R.id.map_layer);
//loading_bar = (ProgressBar) findViewById(R.id.loading_progBar);
content_layout = (RelativeLayout) findViewById(R.id.content_layout);
nodata_layout = (RelativeLayout) findViewById(R.id.nodata_layout);
//fin de declaration de boutons
//chargement des données
progressDialog = new ProgressDialog(this);
progressDialog = new ProgressDialog(MapActivity.this);
progressDialog.setMessage("En cours..."); // Setting Message
progressDialog.setTitle("Chargement de la carte"); // Setting Title
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); // Progress Dialog Style Spinner
progressDialog.show(); // Display Progress Dialog
progressDialog.setCancelable(false);
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
progressDialog.dismiss();
}
}).start();
// fni de chargement des données
//open drawer and load list data in drawer layout button
drawermenugauche.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
openDrawer(drawerLayout);
API.getApiInterface(MapActivity.this).getEvents(api_key, getResources().getString(R.string.lang), 0, new Callback<ApiInterface.GetEventsResult>() {
#Override
public void success(ApiInterface.GetEventsResult result, Response response) {
adapter.setArray(result.items.data);
if(result.items.data.size() != 0)
listevent.setVisibility(View.VISIBLE);
else
nodata_layout1.setVisibility(View.VISIBLE);
listevent.setVisibility(View.GONE);
}
#Override
public void failure(RetrofitError retrofitError) {
Toast.makeText(MapActivity.this, R.string.errorHappened, Toast.LENGTH_SHORT).show();
}
});
}
});
drawer_up.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
closeDrawer(drawerLayout);
}
});
zoomin.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
map.animateCamera(CameraUpdateFactory.zoomIn());
}
});
zoomout.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
map.animateCamera(CameraUpdateFactory.zoomOut());
}
});
zoom_auto.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
isAutoZoomEnabled = !isAutoZoomEnabled;
if (isAutoZoomEnabled)
{
zoom_auto.setImageResource(R.drawable.icon2022);
Toast.makeText(MapActivity.this, "Zoom Auto Activé", Toast.LENGTH_SHORT).show();
} else
{
zoom_auto.setImageResource(R.drawable.disableicon2022);
Toast.makeText(MapActivity.this, "Zoom Auto Désactivé", Toast.LENGTH_SHORT).show();
}
}
});
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
// ouverture et fermeture de drawer
private static void openDrawer(DrawerLayout drawerLayout){
drawerLayout.openDrawer(GravityCompat.START);
}
private static void closeDrawer(DrawerLayout drawerLayout){
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
drawerLayout.closeDrawer(GravityCompat.START);
}
}
//fin ouverture et fermeture drawer
......etc...
see my EventsAdapter code below:
public class EventsAdapter extends AwesomeAdapter<Event> {
public EventsAdapter(Context context) {
super(context);
}
ArrayList<Event> original;
#Override
public void setArray(ArrayList<Event> array) {
super.setArray(array);
if(original == null)
original = array;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
convertView = getLayoutInflater().inflate(R.layout.adapter_events, null);
Event item = getItem(position);
TextView device_name = (TextView) convertView.findViewById(R.id.device_name);
device_name.setText(item.device_name);
TextView date = (TextView) convertView.findViewById(R.id.date);
date.setText(item.time);
TextView message = (TextView) convertView.findViewById(R.id.message);
message.setText(item.message);
TextView geofence_name = (TextView) convertView.findViewById(R.id.geofence_name);
geofence_name.setText(item.geofence_name);
return convertView;
}
ItemFilter mFilter = new ItemFilter();
public Filter getFilter() {
return mFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint)
{
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final ArrayList<Event> nlist = new ArrayList<>();
for(Event item : original)
{
if(item.fitForFilter(filterString))
nlist.add(item);
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
setArray((ArrayList<Event>) results.values);
notifyDataSetChanged();
}
}
}
then in my adapter_event layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:background="#color/whitesplash"
android:layout_marginBottom="10dp"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/instance"
android:layout_width="16dp"
android:layout_height="22dp"
android:src="#drawable/custom_floating_button" />
<TextView
android:id="#+id/device_nam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#+id/instance"
android:fontFamily="#font/fjallaoneregular"
android:text="Info Balise"
android:textColor="#color/black"
android:textSize="8dp"
android:textStyle="normal" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#+id/device_nam"
android:outlineAmbientShadowColor="#color/blue" />
<TextView
android:id="#+id/device_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/device_nam"
android:layout_marginStart="16dp"
android:fontFamily="#font/fjallaoneregular"
android:text="device name"
android:textColor="#color/blue"
android:textSize="8dp"
android:textStyle="italic" />
<TextView
android:id="#+id/textspeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_toEndOf="#+id/device_nam"
android:fontFamily="#font/fjallaoneregular"
android:text="Vitesse"
android:textColor="#color/black"
android:textSize="8dp"
android:textStyle="italic" />
<TextView
android:id="#+id/speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textspeed"
android:layout_marginStart="3dp"
android:layout_toEndOf="#+id/device_name"
android:fontFamily="#font/fjallaoneregular"
android:text="speed"
android:textColor="#color/blue"
android:textSize="8dp"
android:textStyle="italic" />
<TextView
android:id="#+id/message1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:layout_toRightOf="#+id/textspeed"
android:fontFamily="#font/fjallaoneregular"
android:text="message"
android:textColor="#color/black"
android:textSize="8dp"
android:textStyle="normal" />
<TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textspeed"
android:layout_marginStart="3dp"
android:layout_toEndOf="#+id/speed"
android:fontFamily="#font/fjallaoneregular"
android:text="massage"
android:textColor="#color/blue"
android:textSize="8sp"
android:textStyle="italic" />
<View
android:id="#+id/view2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/device_name" />
<TextView
android:id="#+id/datetext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/device_name"
android:layout_toEndOf="#+id/instance"
android:fontFamily="#font/fjallaoneregular"
android:text="date:"
android:textColor="#color/black"
android:textSize="8dp"
android:textStyle="normal" />
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/device_name"
android:layout_marginStart="3dp"
android:layout_toEndOf="#+id/datetext"
android:fontFamily="#font/fjallaoneregular"
android:text="date"
android:textColor="#color/blue"
android:textSize="8sp"
android:textStyle="italic" />
<TextView
android:id="#+id/geofence_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="geofence_name"
android:fontFamily="#font/lobsterregular"
android:layout_below="#+id/date"
android:layout_marginStart="3dp"
android:layout_toRightOf="#+id/instance"
android:textSize="8dp"
android:textColor="#color/blue"/>
</RelativeLayout>
in this adpater_events i have found no mistake. and in the drawer_tracesas i said before( i am not using menu and header in navigationDrawer i would like to use a layout that i called drawer_traces) like below
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/drawerup"
android:orientation="horizontal"
android:background="#color/blue">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/objects"
android:src="#drawable/ic_menu_24"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="16sp"
android:text="#string/objects" />
</LinearLayout>
<TextView
android:id="#+id/Liste_Balises"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/drawerup"
android:fontFamily="#font/fjallaoneregular"
android:gravity="center"
android:text="#string/liste_balises"
android:textColor="#color/blue" />
<LinearLayout
android:id="#+id/list_balises"
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical"
android:layout_below="#+id/Liste_Balises"
android:layout_marginTop="10dp"
android:minHeight="?android:attr/listPreferredItemHeight">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical" />
</LinearLayout>
<TextView
android:id="#+id/list_events"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/list_balises"
android:layout_marginTop="10dp"
android:fontFamily="#font/fjallaoneregular"
android:gravity="center"
android:text="#string/liste_evennemT"
android:textColor="#color/blue" />
<LinearLayout
android:id="#+id/list_event"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/list_events"
android:layout_marginTop="10dp"
android:minHeight="?android:attr/listPreferredItemHeight">
<ListView
android:id="#+id/listevent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical" />
</LinearLayout>
<RelativeLayout
android:id="#+id/nodata_layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/list_event"
android:layout_above="#+id/clearAllEvents"
android:background="#ffffff"
android:visibility="gone"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/noEventsData"/>
</RelativeLayout>
<Button
android:id="#+id/clearAllEvents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/list_event"
android:fontFamily="#font/fjallaoneregular"
android:text="Effacer Evennements"/>
</RelativeLayout>
this layout (drawer_trace) will be displayed in mapActivity as a navigation Drawer. we are ok for that.
and then i have my Events Model:
public class Event
{
public int id, user_id, device_id, position_id, alert_id;
// geofence_id
public String message;
public String address;
public float altitude;
// course
public float latitude, longitude;
// power
public float speed;
public String time;
// deleted
public String device_name, geofence_name;
public boolean fitForFilter(String filterString) {
if(message.toLowerCase().contains(filterString.toLowerCase()))
return true;
if(address.toLowerCase().contains(filterString.toLowerCase()))
return true;
if(time.toLowerCase().contains(filterString.toLowerCase()))
return true;
if(device_name.toLowerCase().contains(filterString.toLowerCase()))
return true;
if(geofence_name.toLowerCase().contains(filterString.toLowerCase()))
return true;
return false;
}
i am using REST API in backend and retrofit.
everything is ok untill i try to eun the app.
it says ERROR MESSAGE:
Process: com.gabontech.gprstest, PID: 14460
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gabontech.gprstest/com.gabontech.gprstest.activities.MapActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3433)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3572)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2097)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:264)
at android.app.ActivityThread.main(ActivityThread.java:7663)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
at com.gabontech.gprstest.activities.MapActivity.onCreate(MapActivity.java:139)
at android.app.Activity.performCreate(Activity.java:7805)
at android.app.Activity.performCreate(Activity.java:7794)
i think about the adapter where in EventsAdapter.class line ref:::::
convertView = getLayoutInflater().inflate(R.layout.adapter_events, null);
ihave spent two days there. please if you can help it will give me a hand for my exam. Thank so much guys
So I have an object with some fields (Two edit text and a radiogroup with two radiobuttons) and I need them all to be completed to create the object, I have all done except the gender (masculino-femenino down boolean down there coming from a from radiobutton). Everything works but the radioButton, How can I know they're empty, I'm running out of logic ideas and I know it have to ve something easy for this, probably obious This is what I have:
```
public boolean camposCompletos() {
if (nombre.isEmpty()) {
return false;
} else if (desc.isEmpty()) {
return false;
}else if (masculino.isChecked() || femenino.isChecked()) {
sexo_comprobacion = false;
return false;
}
return true;
}
```
Try with following code it will help you.
//activity xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="#+id/male"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Male" />
<RadioButton
android:id="#+id/female"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Female" />
</RadioGroup>
<Button
android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click" /> </LinearLayout>
//activity code
public class MainActivity extends AppCompatActivity {
private RadioButton maleRB, femaleRB;
private Button button;
private String selectedOption = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
maleRB = findViewById(R.id.male);
femaleRB = findViewById(R.id.female);
button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (maleRB.isChecked()) selectedOption = maleRB.getText().toString();
if (femaleRB.isChecked()) selectedOption = femaleRB.getText().toString();
Toast.makeText(MainActivity.this,selectedOption,Toast.LENGTH_LONG).show();
}
});
}
}
I'm trying to start another activity after clicking on a CardView inside a RecyclerView. The new activity renders after the click on any of the items inside the RecyclerView (It does the transition and changes the title TextView), but it does not show any of the TextView's inside the CardView on the layout.
The OnClick method is being set as an interface and being implemented in the first Activity.
Here is my first activity. I'm loading the data here from a SQLite database, but it's not relevant for the question to show the code from it.
public class MainActivity extends AppCompatActivity implements RecipeAdapterMain.OnCardListener {
private TextView tv;
ArrayList<RecipeObject> recipes = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rv = findViewById(R.id.recipeListMain);
LinearLayoutManager llm = new LinearLayoutManager(this);
rv.setLayoutManager(llm);
RecipeAdapterMain adapter = new RecipeAdapterMain(recipes, this);
rv.setAdapter(adapter);
tv = findViewById(R.id.title);
}
#Override
public void onCardClick(int position) {
Intent intent = new Intent(this, RecipeActivity.class);
startActivity(intent);
}
}
This is my Adapter.
public class RecipeAdapterMain extends RecyclerView.Adapter<RecipeAdapterMain.RecipeListViewHolder> {
RecyclerView mRecyclerView;
ArrayList<RecipeObject> recipeList;
private OnCardListener mOnCardListener;
public RecipeAdapterMain(Context context, ArrayList<RecipeObject> recipeList, OnCardListener onCardListener) {
this.mOnCardListener = onCardListener;
this.recipeList = recipeList;
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public RecipeListViewHolder onCreateViewHolder(ViewGroup parent, int i) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_recipe_main, parent, false);
RecipeListViewHolder rcv = new RecipeListViewHolder(layoutView, mOnCardListener);
return rcv;
}
#Override
public void onBindViewHolder(#NonNull RecipeListViewHolder holder, int position) {
holder.mName.setText(recipeList.get(position).getName());
}
#Override
public int getItemCount(){
return recipeList.size();
}
public class RecipeListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView mName;
OnCardListener onCardListener;
public RecipeListViewHolder(final View view, OnCardListener onCardListener) {
super(view);
mName = view.findViewById(R.id.textViewTitle);
this.onCardListener = onCardListener;
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onCardListener.onCardClick(getAdapterPosition());
}
}
public interface OnCardListener {
void onCardClick(int position);
}
}
My second activity:
public class RecipeActivity extends AppCompatActivity {
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.layout_recipe);
}
}
This is the layout from the second activity. (layout_recipe):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a test"
android:textColor="#1A1A1A"
android:textSize="18sp" />
<TextView
android:id="#+id/textViewIngr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a test"
android:textColor="#1A1A1A"
android:textSize="18sp" />
<TextView
android:id="#+id/textViewDire"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a test"
android:textColor="#1A1A1A"
android:textSize="18sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
And this is the layout from the first activity (activity_main):
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recipeListMain"
android:scrollbars="vertical">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundTint="#color/colorAccent"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:layout_marginBottom="16dp"
android:contentDescription="#string/submit"
android:src="#drawable/ic_add_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:onClick="openActivityCreate"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
From clicking in a Card on the MainActivity, I expected to render the second activity with it's TextViews (This is a test), but it's rendering a blank page instead.
try removing #Nullable PersistableBundle persistentState from onCreate on your second activity
I have a PreferenceFragment containing some TextEditPreferences etc. and then I have this custom Preference that uses Volley NetworkImageView instead of the default ImageView and has a "Go to" icon at the end. Layout-wise otherwise it's copy-pasted from compat-v14 preference.xml file.
The problem is, I can't get any focus, selection or click events to fire when touching the Custom Preference item. I've tries everything I've come up: onClick(), onPreferenceTreeClick(), setOnPreferenceClickListener, setting layout xml android:selectable="true", android:enabled="true", android:descendantFocusability="blocksDescendants"...
xml/preferences.xml
<PreferenceCategory android:title="Icon">
<dev.niko.project.views.GravatarIconPreference android:key="auth.user.avatar"
android:title="Gravatar" android:summary="This has no focus animation, no click events are fired and certainly no Intent"
android:selectable="true" android:enabled="true"
android:layout="#layout/preference_gravatar"
android:defaultValue="">
<intent android:action="android.intent.action.VIEW" android:data="https://en.gravatar.com/connect/" />
</dev.niko.project.views.GravatarIconPreference>
<Preference
android:title="Gravatar" android:summary="This works fine">
<intent android:action="android.intent.action.VIEW" android:data="https://en.gravatar.com/connect/" />
</Preference>
</PreferenceCategory>
MyPreferencesFragment.java
public class AccountSettingsFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
preferences = context.getSharedPreferences(PREF_NAME_AUTH, Context.MODE_PRIVATE);
GravatarIconPreference gravatarIconPref = ((GravatarIconPreference)findPreference(AVATAR));
gravatarIconPref.setImageUrl(API.gravatar(preferences.getString(EMAIL, null)));
gravatarIconPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
Log.wtf(TAG, "gravatarIconPref.onPreferenceClick()");
return false;
}
});
for (String key : preferences.getAll().keySet()) {
onSharedPreferenceChanged(preferences, key);
}
}
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
Log.wtf(TAG, "onPreferenceTreeClick(..., "+preference.getKey()+")");
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
final Preference preference = findPreference(key);
if (preference != null) {
Log.d(TAG, "onSharedPreferenceChanged. key="+key+" preference.getKey="+preference.getKey());
}
}
}
GravatarIconPreference.java
public class GravatarIconPreference extends Preference {
private static final String TAG = GravatarIconPreference.class.getSimpleName();
private Context context;
private View view;
private Drawable icon;
private String url;
public GravatarIconPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setSelectable(true);
setEnabled(true);
this.context = context;
}
// also tried overriding onCreateView, no change
#Override
protected void onBindView(View view) {
super.onBindView(view);
view.setClickable(true);
if (view != null && !TextUtils.isEmpty(url)) {
NetworkImageView gravatar = ((NetworkImageView) view.findViewById(R.id.gravatar));
if (gravatar != null) {
gravatar.setImageUrl(url, App.getInstance().getImageLoader());
}
}
}
#Override
protected void onClick() {
Log.wtf(TAG, "onClick()!!!");
super.onClick();
}
#Override
public Drawable getIcon() {
// TODO: gravatar-networkimageview
return super.getIcon();
}
public void setImageUrl(#Nullable String url) { this.url = url; }
}
preference_gravatar.xml source
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/activatedBackgroundIndicator"
android:clipToPadding="false"
android:focusable="true" android:descendantFocusability="blocksDescendants"
android:baselineAligned="false">
<LinearLayout android:id="#+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="-4dp"
android:minWidth="60dp"
android:gravity="start|center_vertical"
android:orientation="horizontal"
android:paddingEnd="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp" android:focusable="false">
<com.android.volley.toolbox.NetworkImageView android:id="#+id/gravatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:maxWidth="48dp"
app:maxHeight="48dp"
android:layout_marginStart="#dimen/list_icon_margin"
android:layout_gravity="center" />
</LinearLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView android:id="#android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"
android:layout_alignParentStart="true"
android:layout_toStartOf="#+id/chevron"/>
<TextView android:id="#android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
android:layout_alignParentStart="true"
android:layout_toStartOf="#+id/chevron"/>
<ImageView android:id="#+id/chevron"
android:src="#mipmap/ic_chevron_right_black_48dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:alpha="0.5"
android:contentDescription="go to url" />
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<LinearLayout android:id="#android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:paddingStart="16dp"
android:orientation="vertical" />
</LinearLayout>
For custom preference, you need to set the click listener programmatically.
#Override
protected void onBindView(View view) {
super.onBindView(view);
view.setClickable(true);
if (view != null && !TextUtils.isEmpty(url)) {
NetworkImageView gravatar = ((NetworkImageView) view.findViewById(R.id.gravatar));
if (gravatar != null) {
gravatar.setImageUrl(url, App.getInstance().getImageLoader());
gravatar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i("test","clicked");
}
}
}
}
}