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.
Related
Android studio does not recognize a method within my code.
I implemented a method to handle the call.
private void saveDeal(){
String title = textTitle.getText().toString();
String description = textDescription.getText().toString();
String price = textPrice.getText().toString();
TravelDeal deal = new TravelDeal(title, description, price, "");
mDatabaseReference.push().setValue(deal);
}
private void clean(){
textTitle.setText("");
textDescription.setText("");
textPrice.setText("");
textTitle.requestFocus();
}
But in the method call,
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_save:
saveDeal();
Toast.makeText(this, "Deal saved", Toast.LENGTH_LONG);
clean();
return true;
default:
return super.onOptionsItemSelected(item);
}
saveDeal() and clean() are still showing in red in the switch block.
Found a solution. I missed a closing curly bracket in the switch statement in the onOptionsItemsSelectedMenu() method.
From Android Studio Menu, Try File->Invalidate Caches/Restart->Invalidate and Restart
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);
I am using a fragment which shows differnet informations about an object. Inside onCreate of the fragment I retrieve some values from the object and store them in global variables:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
String serializedShow = getArguments().getString(SHOW_TO_LOAD);
mShow = (new Gson()).fromJson(serializedShow, Show.class);
mScope = mShow.getScope();
mLanguage = MainActivity.getSystemLanguage();
mLanguage = mLanguage.replace("_", "-");
mId = Integer.valueOf(mShow.getShowId()).toString(); //this line is important
Log.v(LOG_TAG, "DetailFragment onStart, Id is " + mId);
}
As you can see I assign to this variable a specific ID. I use the log to check if the value of mId is the correct one and it is. Everything works well so far.
Next int he code the user can click a button to upen up am url in the browser. The URls are different with each time this fragment is created (every time this fragment shows different stuff)
private void fetchIMDBId(){
Log.v(LOG_TAG, "starting IMDBAsyncTask with id " + mId);
new Async4().execute(mId);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_launch:
fetchIMDBId();
return true;
default:
break;
}
return false;
}
As you can see the method fetchIMDBId() gets called. I have a log line to check if the value of mId which was set before in onCreate is the same.
It is not the same, its a totally different value.
Specifically is the id of the object that was being displayed in a previous instance if this fragment.
Please tell me what I'm doing wrong. Thanks.
E: variable declaration
public class DetailFragment extends Fragment {
private static final String LOG_TAG = DetailFragment.class.getSimpleName();
...
private String mScope, mLanguage, mId;
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
}
E: full source here
I believe you are not assigning your mId correctly to the Async task. You should apply the mid to the async task method so that the corresponding mId from each fragment is called
private void fetchIMDBId(String mId){
Log.v(LOG_TAG, "starting IMDBAsyncTask with id " + mId);
new Async4().execute(mId);
}
and then call the method within the fragment
fetchIMDBId(this.mId);
Try using this.mId and also check if your fragment object is same as previous one.
Call this.fetchIMDBId() instead.
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);