I'm working on my first Android app and I have one issue I cannot sorted. I checked out stack overflow but I cannot find the solution.
I have a menu which show 4 different Activities when menu item is selected.
I also have a class which manage the menu:
public class TabMenuManager {
final Context context;
public TabMenuManager(Context context) {
this.context = context;
}
public boolean handleTabMenuAction(int item) {
Log.d("Toolstrea", "TAB MENU HANDLED: " + item);
switch (item) {
case R.id.action_home:
handleHomeAction();
return true;
case R.id.action_reorder:
handleReOrderAction();
return true;
//.....
}
private void handleReOrderAction() {
if (this.context.getApplicationContext() instanceof ReOrderActivity) {
Log.d("Toolstream", "REORDER CLASSES THE SAME");
Intent reOrderIntent = new Intent(this.context, ReOrderActivity.class);
reOrderIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.context.startActivity(reOrderIntent);
}
else
Log.d("Toolstream", "REORDER CLASSES NOT THE SAME");
}
private void handleHomeAction() {
// Simmilar as one above
}
}
In all activities I show the menu I just call:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
TabMenuManager tmm = new TabMenuManager(getApplicationContext());
boolean success = tmm.handleTabMenuAction(item.getItemId());
if (!success) {
return super.onOptionsItemSelected(item);
}
return success;
}
This class just simple show activity but I want to make sure it won't present the same activity as current one.
In this example I use:
this.context.getApplicationContext() instance of ReOrderActivity
But I also tried
this.context.getClass() == HomeActivity.class
It always log that the activity are different.
It cause the problem that if I'm in HomeActivity I can press Home in my menu and another instance of HomeActivity will be added on the stack and so on.
How can I make sure I present just one instance of the activity?
Is there a better way I doing that?
Many thanks.
In your code, this.context.getApplicationContext() instance of ReOrderActivity can never be true. You should change it to: this.context instance of ReOrderActivity
You also need to change how you create your TabMenuManager in onOptionsItemSelected. Change it to: TabMenuManager tmm = new TabMenuManager(this);
Related
Currently I am working on an app which has a bottom navbar with three menu items. I had used setOnNavigationItemSelectedListener() for items being clicked. but now iam facing issue that the method has been depreciated.
App Language: Java
Issue: 'setOnNavigationItemSelectedListener(com.google.android.material.bottomnavigation.BottomNavigationView.OnNavigationItemSelectedListener)' is deprecated
Is there any way to resolve it? is is there any better alternative than setOnNavigationItemSelectedListener() method.
Its deprecated according to github sources: BottomNavigationView.setOnNavigationItemSelectedListener
In its comment you can read:
#deprecated Use {#link NavigationBarView#setOnItemSelectedListener(OnItemSelectedListener)}
* instead.
so use NavigationBarView.setOnItemSelectedListener from its base class:
/**
* Set a listener that will be notified when a navigation item is selected. This listener will
* also be notified when the currently selected item is reselected, unless an {#link
* OnItemReselectedListener} has also been set.
*
* #param listener The listener to notify
* #see #setOnItemReselectedListener(OnItemReselectedListener)
*/
public void setOnItemSelectedListener(#Nullable OnItemSelectedListener listener) {
selectedListener = listener;
}
Also see this commit
as it explains confusion about this change:
The listeners were deprecated in favor of
NavigationBarView#OnItemSelectedListener and
NavigationBarView#OnItemReselectedListener, but deprecation
documentation was never added, so it's unclear what developers should
use instead.
you can try setonItemSelectedListener. It is working same as setOnNavigationItemSelectedListener()[tested in android 11]
bnv.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
switch(id){
//check id
}
return true;
}
});
Kotlin:
bnv.setOnItemSelectedListener { item ->
when (item.itemId) {
}
true
}
We can use setOnItemSelectedListener instead of setOnNavigationItemSelectedListener and
setOnItemReselectedListener instead of setOnNavigationItemReselectedListener
navView.setOnItemSelectedListener {
// do something
true
}
// In case the default menu can be the first menu
// Should set the default selected menu BETWEEN setOnItemSelectedListener and setOnItemReselectedListener.
// It will make setOnItemSelectedListener fired when you launch app.
// If you set default menu AFTER setOnItemReselectedListener.
// Then setOnItemReselectedListener will fired when you launch app
navView.selectedItemId = R.id.navigation_home
navView.setOnItemReselectedListener {
// do something
}
you can use in Kotlin
buttmNav.setOnItemSelectedListener { item ->
when (item.itemId) {
}
true
}
viewBindingMainActivity.navView.setOnItemSelectedListener { menuItem ->
if (menuItem.itemId != R.id.navigation_home) {
Add your code
false
} else {
Add your code
true
}
}
kotlin:
use setOnItemSelectedListener
bottomNavigationView.setOnItemSelectedListener { item: MenuItem ->
when (item.itemId) {
R.id. ... -> {
Add your code
true
}
else ->
true
}
public class HomeActivity extends AppCompatActivity implements NavigationBarView.OnItemSelectedListener {
BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
bottomNavigationView = findViewById(R.id.bottom_nav);
bottomNavigationView.setOnItemSelectedListener(this);
displayfragment(new FragmentHome());
}
private void displayfragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.content_area, fragment).commit();
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()) {
case R.id.nav_home:
fragment = new FragmentHome();
break;
case R.id.nav_fav:
fragment = new FavouriteFragment();
break;
case R.id.nav_set:
fragment = new FragmentSetting();
break;
default:
fragment = new FragmentHome();
break;
}
displayfragment(fragment);
return true;
}
}
I have created a private member of the whole class called Member curMbr;
The activity (rather the fragment, since this is in a frament class) has a listview
with some contributions from members.
I also have a context menu on that list. When clicking on a contribution, I want a (customized) dialog box to show details about the member. (Member ID is part of the contribution objet. )
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Log.d("FRGCOTIZ02", "create ctxt menu");
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
String[] menuItems = getResources().getStringArray(R.array.ar_menu_ctxt_participant);
// Get selected member
Contribution curCotis = (Contribution) (((ListView)v).getItemAtPosition(info.position));
Participant p = new Participant(helper.getDBItem(DBHelper.TABLE_PARTICIPANT,
DBHelper.COL_ID, curCotis.getParticipant()));
curMbr = new Member(helper.getDBItem(DBHelper.TABLE_MEMBER, DBHelper.COL_ID, p.getMember()));
for (int i = 0; i < menuItems.length; i++) {
menu.add(Menu.NONE, i, i, menuItems[i]);
}
Log.d("FRGCOTIZ01", curMbr.getId_());
}
#Override
public boolean onContextItemSelected(MenuItem item) {
return ( applyContextMenuSelection(item) || super.onContextItemSelected(item) );
}
private boolean applyContextMenuSelection(MenuItem item) {
switch (item.getItemId()) {
case 0: // Summary
final Dialog dlg = new Dialog(this.getContext());
final String sessID;
try {
sessID = KUtil.DATE_FORMAT.format(curSess.getDate());
dlg.setContentView(R.layout.alert_show_charges);
Button btnOK = dlg.findViewById(R.id.btn_alertOK);
btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setupAlertDialogCharges(dlg, sessID, curMbr.getId_());
}
});
Button btnCancel = dlg.findViewById(R.id.btn_alertCancel);
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dlg.dismiss();
}
});
dlg.show();
} catch (Exception e){
Log.d("FRAGMENT Contribution", e.getMessage());
}
break;
case 1: // Collect
break;
case 2: // Cancel
break;
default:
break;
}
return true;
}
In method onCreateContextMenu, I can get the member and display his ID.
But in method applyContextMenuSelection, there is an exception, saying the meber is null!
Funny enough there is another variable that I am using in that method, and it works fine. Difference is, that variable has been set at creation of the fragment.
How do I solve this?
I have been studying the code for a while and the only thing I could figure was that the issue is somehow linked to the use of contextmenu. It seems to me that variables are set back to their original when the menu action is supposed to be executed. Again, I am not too sure about that.
So, the only solution I found so far was to keep that vale in a "higher" context:
When I can still read the value,
getActivity().getIntent().putExtra(HomeActivity.ID_ENTRY, curMbr.getId_());
When I want to use it,
final String mbrID = getActivity().getIntent().getStringExtra(HomeActivity.ID_ENTRY);
I've been struggling with this for some time now and could not find a solution. Currently I'm population my RecyclerView with all the installed apps on the device using PackageManager. This works perfectly, here is the result I get:
The issue I'm having is that I can't figure out how to store/retrieve the selected checkbox, let me elaborate.
When I select a Checkbox I do the following inside onBindViewHolder:
holder.mAppSelect.setOnCheckedChangeListener(null);
holder.mAppSelect.setChecked(mDataSet.get(position).isSelected());
holder.mAppSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mDataSet.get(position).setSelected(isChecked);
if (holder.mAppSelect.isChecked()){
//Ok great, I can use this to get the position, package name and app name that was selected/checked
}else{
//and it was un-sellected
}
So, I can used the above to store the package name of the selected checkbox and also store a boolean of the state of the checkbox in SQLite, like this:
holder.mAppSelect.setOnCheckedChangeListener(null);
holder.mAppSelect.setChecked(mDataSet.get(position).isSelected());
holder.mAppSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mDataSet.get(position).setSelected(isChecked);
if (holder.mAppSelect.isChecked()){
dbManager.insert(holder.mTextViewPackage.getText().toString(), true);
}else{
dbManager.insert(holder.mTextViewPackage.getText().toString(), false);
}
This is where I have difficulty.. Lets say I close the Activity and open it again, I would like to get the packages/checkboxes that was selected from SQLite and set it again.
So, I'm looking for a way to "cycle" though each holder, get the package name from the holder so that I can check in SQLite if the checkbox was selected previously and set it accordingly.
I think it's also worth mentioning that applications may have been uninstalled or installed since the last time the application was launched. So that would mean that the getAdapterPosition will not remain the same.
EDIT 1:
This is how I populate the Array called mDataSet:
public class AppManager {
private Context mContext;
private AppInfo appInfo;
private ArrayList<AppInfo> myApps;
public AppManager(Context c) {
mContext = c;
myApps = new ArrayList<AppInfo>();
}
public ArrayList<AppInfo> getApps() {
loadApps();
return myApps;
}
private void loadApps() {
List<ApplicationInfo> packages = mContext.getPackageManager().getInstalledApplications(0);
for (ApplicationInfo packageInfo : packages) {
AppInfo newApp = new AppInfo();
newApp.setAppName(getApplicationLabelByPackageName(packageInfo.packageName));
newApp.setAppPackage(packageInfo.packageName);
newApp.setAppIcon(getAppIconByPackageName(packageInfo.packageName));
myApps.add(newApp);
}
Collections.sort(myApps, new Comparator<AppInfo>() {
#Override
public int compare(AppInfo s1, AppInfo s2) {
return s1.getAppName().compareToIgnoreCase(s2.getAppName());
}
});
}
// Custom method to get application icon by package name
private Drawable getAppIconByPackageName(String packageName) {
Drawable icon;
try {
icon = mContext.getPackageManager().getApplicationIcon(packageName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
// Get a default icon
icon = ContextCompat.getDrawable(mContext, R.drawable.ic_launcher_background);
}
return icon;
}
// Custom method to get application label by package name
private String getApplicationLabelByPackageName(String packageName) {
PackageManager packageManager = mContext.getPackageManager();
ApplicationInfo applicationInfo;
String label = "Unknown";
try {
applicationInfo = packageManager.getApplicationInfo(packageName, 0);
if (applicationInfo != null) {
label = (String) packageManager.getApplicationLabel(applicationInfo);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return label;
}
}
what you can do is use shared preferences
when you start activity retrive state from shared preference like this
SharedPreferences sharedPreference PreferenceManager.getDefaultSharedPreferences(getAppContext());
for(i=0;i<mDataSet.size();i++)
{
mDataSet.get(i).setSelected(sharedPreference.getBoolean(mDataSet.get(i).getAppPackage(),false));
}
and in your adapter save state like this.
holder.mAppSelect.setOnCheckedChangeListener(null);
holder.mAppSelect.setChecked(mDataSet.get(position).isSelected());
holder.mAppSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mDataSet.get(position).setSelected(isChecked);
sharedPreference.edit().putBoolean(mDataSet.get(position).getAppPackage(), isChecked).commit();
});
As I can see, you are following the right steps to show the checkbox selected, if isSelected() returns true, and to save the state(checked/unckecked) of the checkbox in SQLite.
TO display the saved state of the checkboxes from SQLite when you close and open the Activity again, you just need to do is:
First, you need to get the latest list of installed packages.
Select data/checkbox values from SQLite where package name matches with the
latest list of packages.
Now, as you have the saved checkbox values from SQLite, create data set
using the latest installed app list and the checkbox values which you
got from SQLite.
Pass it to your RecyclerViewAdeptor.
It should work fine.
You can try OnClickListener instead of OnCheckedChangeListener
Try this method,
1.Use a list which will have selected items. //selectedlist
If you want to store it permanantly, then use SharedPref.
2.Choose item's data which will be unique //appname as string
3.Set checked state based on the selected list item.
if(selectedlist.get(appname)!=null
&& (selectedlist.get(appname).equals("selected"))) {
holder.checkBox.setChecked(true);
}
else {
holder.checkBox.setChecked(false);
}
4. Add listener to your checkbox,
View.OnClickListener listener=new View.OnClickListener() {
#Override
public void onClick(View v) {
if (selectedlist.get(appname)==null) {
selectedlist.put(appname, "selected");
else if (selectedlist.get(appname).equals("selected"))
selectedlist.put(appname, "not selected");
else
selectedlist.put(appname, "selected");
notifyDataSetChanged();
}
};
holder.checkBox.setOnClickListener(listener);
In this onLoadFinished method I get the content of a particular database column and set it on an EditView (mEditView), the id of which has been defined earlier in OnCreate method:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
if (cursor.moveToFirst())
{
int textColumnIndex = cursor.getColumnIndex(NoteEntry.COLUMN_TEXT);
String content = cursor.getString(textColumnIndex);
mEditView.setText(content);
}
Now I need to use the variable "content" outside this method. For example, I write a method to make a toast message containing the "content" appear on the screen:
private void displayContent(String content)
{
Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
}
I want this toast to be displayed when an Actionbar menu button is clicked. But here a face a problem - when I include displayContent(String content) in OnOptionsItemSelected, I get an error because the variable "content" is not being recognized.
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.display_toast:
displayContent(String text);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
Passing "String content" as second input to onOptionsItemSelected also doesn't solve the problem. I'm new to Android programming, and despite of spending a lot of time searching for a solution on the web I couldn't find an answer. So I would be very thankful for any help.
The line displayContent(String text) is basically creating a new variable text and then feeding that to the method, so it is empty. You have to save the variable as a global variable in your Activity, then you can access it in onOptionItemSelected. So it would be like this:
public class MyActivity extends Activity {
private String content;
then later in onLoadFinished you do not create a new variable you use that one
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
if (cursor.moveToFirst())
{
int textColumnIndex = cursor.getColumnIndex(NoteEntry.COLUMN_TEXT);
content = cursor.getString(textColumnIndex);
mEditView.setText(content);
}
then in onOptionItemSelected you use content as a parameter of your method:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.display_toast:
displayContent(content);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
Study up on the difference between local and global variables and this will make sense to you.
I'm developing a shopping cart app in android and a novice. I have been facing one problem now.
I can add an item and it adds it to the cart. I can edit the quantity of an item or remove it from the listview after I have added it to the cart.
So what I want is to disable the addToCart button if it is present in the cart already in order to avoid duplicates. But every entry into a product is taken as a new entry. I think I have not referenced it properly. Any help would be appreciated.
This is the Activity that gets called every time you press an item (for example: Dell inside Laptops category)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.productdetails);
LayoutInflater li;
final List<Product> cart = ShoppingCartHelper.getCart();// get all //items from cart
int productIndex = getIntent().getExtras().getInt(
ShoppingCartHelper.PRODUCT_INDEX);// the item no in the list
String PRODUCT_STRING = getIntent().getExtras().getString("PRODUCT");
switch (PRODUCT_STRING) {
case "Laptops":
catalog = ShoppingCartHelper.getLaptopCatalog(getResources())
break;
case "Phones":
catalog = ShoppingCartHelper
.gePhonesCatalog(getResources());
break;
}
final Product selectedProduct=(Product)this.catalog.get(productIndex);
// this declaration of product is taken as a new entry......................
ImageView productImageView = (ImageView) findViewById(R.id.ImageViewProduct);
productImageView.setImageDrawable(selectedProduct.productImage); TextView productTitleTextView = (TextView)findViewById(R.id.TextViewProductTitle);
productTitleTextView.setText(selectedProduct.title);
TextView productDetailsTextView = (TextView) findViewById(R.id.TextViewProductDetails);
productDetailsTextView.setText(selectedProduct.description);
final Button addToCartButton = (Button) findViewById(R.id.ButtonAddToCart);
addToCartButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
cart.add(selectedProduct);
selectedProduct.quantity ++;
finish();
}
});
if(cart.contains(selectedProduct)) {
addToCartButton.setEnabled(false);
addToCartButton.setText("Item in Cart");
}
}
The fastest workaround to this would be to override the item's equals().
Otherwise, every instance of your item will be considered (and really is) different from Java's perspective.
Here's how you could do it:
// Somewhere in your item's class..
#Override
public boolean equals(Object o) {
if(!(o instanceof YourItem)
return false;
YourItem i = (YourItem) o;
// This line below is based on my assumption, you should change to better suit your usecase.
return this.getItemId() == i.getItemId();
}
Of course in above code I assume that your item has a field for an item ID and a getter method to obtain it. Do note that it might not suit you and that you might have to make some adaptation to it.