Android studio's run button does not work [duplicate] - android

I'm toying with Android Studio making a very simple very stupid app to learn about saving key preferences and I ran into a weird obstacle. I'll try to provide as much as I can since it may be hard to reproduce this bug but honestly both apps I'm running are super basic and there no compile errors.
Specs:
No emulator, I'm running a Samsung Galaxy Tablet. Windows 7, Android Studio 1.2, Gradle 2.2.1.
In the question title, I mean that I have a project named Kitty (pretty much hello world and a button). I click Run->'Run app'->(Dialogue box opens)->OK->Within moments the app launches on my tablet.
^^^THIS IS THE BEAUTIFUL SCREEN I WANT TO SEE ON Sharedpreferences, but it's only on kitty.
Now I started another project called SharedPreferences (gist: two checkboxes ask you "do you like chocolate" and "do you like luigi" and you check one none or both and press save. Two textviews underneath will update to say if you like those things and even later if you reopen the app the textviews will remember Chocolate Luigi preferences). It is just a main_activity.
I don't think I changed any settings or project preferences between the two and neither give me an error. MainActivity.java OUTDATED ORIGINAL SEE EDIT:
package gaga.sharedpreferences;
import android.content.SharedPreferences;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
public final class setup extends MainActivity {
public void setup () {
//Nothing to see here!
}
// Define the File of Prefs; created if nonexistent
public static final String PREFS_NAME = "MyPrefsFile";
// Start up
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
// Restore preferences on Startup
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean Chocolate = settings.getBoolean("checkChocolate", false);
boolean Luigi = settings.getBoolean("checkLuigi", false);
// Function set to Whatever
// setSilent(silent);
/* Note:
* CheckedTextView and CheckBox::isChecked()
* CheckBox::setChecked()
* */
CheckBox checkHandleChocolate = (CheckBox) findViewById(R.id.checkChocolate);
CheckBox checkHandleLuigi = (CheckBox) findViewById(R.id.checkLuigi);
// What was the preference? On Start set it to the bool it left off in
checkHandleChocolate.setChecked(Chocolate);
checkHandleLuigi.setChecked(Luigi);
// Change report text on Start
TextView buttonHandleChocolate = (TextView) findViewById(R.id.chocolate);
TextView buttonHandleLuigi = (TextView) findViewById(R.id.luigi);
if(Chocolate)
buttonHandleChocolate.setText("I do prefer Chocolate");
else
buttonHandleChocolate.setText("I do not prefer Chocolate");
if(Luigi)
buttonHandleLuigi.setText("I do prefer Luigi");
else
buttonHandleLuigi.setText("I do not prefer Luigi");
}
public void saveChocolate(Boolean c) {
// All objects from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("Chocolate", c);
// Commit the edits
editor.commit();
}
public void saveLuigi(Boolean l) {
// All objects from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("Chocolate", l);
// Commit the edits
editor.commit();
}
}
#Override
protected void onStop(){
super.onStop();
// Objects are from android.context.Context
//Normally I'd put the edit commits here, but that's not true
}
// Clicks on Done
public void userDone (View view) {
// View is which widget
boolean checked = ((CheckBox) view).isChecked();
// Which checkbox was clicked
switch(view.getId()) {
case R.id.checkChocolate:
setup instance1 = new setup();
instance1.saveChocolate(checked);
// No break; continue along
case R.id.checkLuigi:
setup instance2 = new setup();
instance2.saveLuigi(checked);
break;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Red parts of logcat:
06-02 20:49:57.245 25557-25557/? I/SDP.PUB_CRYPTOD﹕ Starting
06-02 20:49:57.245 25557-25557/? I/SDP.PUB_CRYPTOD﹕ Socket created with fd:-1
06-02 20:49:57.245 25557-25557/? E/SDP.PUB_CRYPTOD﹕ Failed to open the netlink socket with error: Protocol not supported
06-02 20:49:57.245 25557-25557/? E/SDP.PUB_CRYPTOD﹕ Exiting
06-02 20:49:59.995 2866-3012/? V/AlarmManager﹕ waitForAlarm result :8
06-02 20:50:02.280 25633-25633/? I/SDP.PUB_CRYPTOD﹕ Starting
06-02 20:50:02.280 25633-25633/? I/SDP.PUB_CRYPTOD﹕ Socket created with fd:-1
06-02 20:50:02.280 25633-25633/? E/SDP.PUB_CRYPTOD﹕ Failed to open the netlink socket with error: Protocol not supported
06-02 20:50:02.280 25633-25633/? E/SDP.PUB_CRYPTOD﹕ Exiting
Thanks for any help. I haven't seen this issue while prowling the internet so it might be excessively noob.
EDIT: Rewritten with the only onCreate in the larger MainActivity class
package gaga.sharedpreferences;
import android.content.SharedPreferences;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
public final class setup extends MainActivity {
public void setup () {
//Nothing to see here!
}
// Define the File of Prefs; created if nonexistent
public static final String PREFS_NAME = "MyPrefsFile";
// Start up
public void onCreateSubclass() {
// super.onCreate(state);
// Restore preferences on Startup
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean Chocolate = settings.getBoolean("checkChocolate", false);
boolean Luigi = settings.getBoolean("checkLuigi", false);
// Function set to Whatever
// setSilent(silent);
/* Note:
* CheckedTextView and CheckBox::isChecked()
* CheckBox::setChecked()
* */
CheckBox checkHandleChocolate = (CheckBox) findViewById(R.id.checkChocolate);
CheckBox checkHandleLuigi = (CheckBox) findViewById(R.id.checkLuigi);
// What was the preference? On Start set it to the bool it left off in
checkHandleChocolate.setChecked(Chocolate);
checkHandleLuigi.setChecked(Luigi);
// Change report text on Start
TextView buttonHandleChocolate = (TextView) findViewById(R.id.chocolate);
TextView buttonHandleLuigi = (TextView) findViewById(R.id.luigi);
if(Chocolate)
buttonHandleChocolate.setText("I do prefer Chocolate");
else
buttonHandleChocolate.setText("I do not prefer Chocolate");
if(Luigi)
buttonHandleLuigi.setText("I do prefer Luigi");
else
buttonHandleLuigi.setText("I do not prefer Luigi");
}
public void saveChocolate(Boolean c) {
// All objects from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("Chocolate", c);
// Commit the edits
editor.commit();
}
public void saveLuigi(Boolean l) {
// All objects from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("Chocolate", l);
// Commit the edits
editor.commit();
}
}
#Override
protected void onStop(){
super.onStop();
// Objects are from android.context.Context
//Normally I'd put the edit commits here, but that's not true
}
// Clicks on Done
public void userDone (View view) {
// View is which widget
boolean checked = ((CheckBox) view).isChecked();
// Which checkbox was clicked
switch(view.getId()) {
case R.id.checkChocolate:
setup instance1 = new setup();
instance1.saveChocolate(checked);
// No break; continue along
case R.id.checkLuigi:
setup instance2 = new setup();
instance2.saveLuigi(checked);
break;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setup startInstance = new setup();
startInstance.onCreateSubclass();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

In Android Studio you need create a Run Configuration in your project.
Go to this link to left run icon
And click on Edit Configuration, after in the windows configure like this:
And save it, for test click run icon.

It appears that you have two onCreate methods. Try removing the second one and running it again.

Related

How to implement permanent splash screen and 1 time tutorial both in one app [duplicate]

This question already has answers here:
Determine if Android app is being used for the first time
(15 answers)
Closed 6 years ago.
I am new to android development and and I want to setup some of application's attributes based on Application first run after installation. Is there any way to find that the application is running for the first time and then to setup its first run attributes?
The following is an example of using SharedPreferences to achieve a 'first run' check.
public class MyActivity extends Activity {
SharedPreferences prefs = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Perhaps set content view here
prefs = getSharedPreferences("com.mycompany.myAppName", MODE_PRIVATE);
}
#Override
protected void onResume() {
super.onResume();
if (prefs.getBoolean("firstrun", true)) {
// Do first run stuff here then set 'firstrun' as false
// using the following line to edit/commit prefs
prefs.edit().putBoolean("firstrun", false).commit();
}
}
}
When the code runs prefs.getBoolean(...) if there isn't a boolean saved in SharedPreferences with the key "firstrun" then that indicates the app has never been run (because nothing has ever saved a boolean with that key or the user has cleared the app data in order to force a 'first run' scenario). If this isn't the first run then the line prefs.edit().putBoolean("firstrun", false).commit(); will have been executed and therefore prefs.getBoolean("firstrun", true) will actually return false as it overrides the default true provided as the second parameter.
The accepted answer doesn't differentiate between a first run and subsequent upgrades. Just setting a boolean in shared preferences will only tell you if it is the first run after the app is first installed. Later if you want to upgrade your app and make some changes on the first run of that upgrade, you won't be able to use that boolean any more because shared preferences are saved across upgrades.
This method uses shared preferences to save the version code rather than a boolean.
import com.yourpackage.BuildConfig;
...
private void checkFirstRun() {
final String PREFS_NAME = "MyPrefsFile";
final String PREF_VERSION_CODE_KEY = "version_code";
final int DOESNT_EXIST = -1;
// Get current version code
int currentVersionCode = BuildConfig.VERSION_CODE;
// Get saved version code
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
int savedVersionCode = prefs.getInt(PREF_VERSION_CODE_KEY, DOESNT_EXIST);
// Check for first run or upgrade
if (currentVersionCode == savedVersionCode) {
// This is just a normal run
return;
} else if (savedVersionCode == DOESNT_EXIST) {
// TODO This is a new install (or the user cleared the shared preferences)
} else if (currentVersionCode > savedVersionCode) {
// TODO This is an upgrade
}
// Update the shared preferences with the current version code
prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply();
}
You would probably call this method from onCreate in your main activity so that it is checked every time your app starts.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkFirstRun();
}
private void checkFirstRun() {
// ...
}
}
If you needed to, you could adjust the code to do specific things depending on what version the user previously had installed.
Idea came from this answer. These also helpful:
How can you get the Manifest Version number from the App's (Layout) XML variables?
User versionName value of AndroidManifest.xml in code
If you are having trouble getting the version code, see the following Q&A:
How to get the build/version number of your Android application?
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID;
import android.content.Context;
public class Util {
// ===========================================================
//
// ===========================================================
private static final String INSTALLATION = "INSTALLATION";
public synchronized static boolean isFirstLaunch(Context context) {
String sID = null;
boolean launchFlag = false;
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists()) {
launchFlag = true;
writeInstallationFile(installation);
}
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return launchFlag;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");// read only mode
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}
> Usage (in class extending android.app.Activity)
Util.isFirstLaunch(this);
There is no way to know that through the Android API. You have to store some flag by yourself and make it persist either in a SharedPreferenceEditor or using a database.
If you want to base some licence related stuff on this flag, I suggest you use an obfuscated preference editor provided by the LVL library. It's simple and clean.
Regards,
Stephane
I'm not sure it's good way to check it. What about case when user uses button "clear data" from settings? SharedPreferences will be cleared and you catch "first run" again. And it's a problem. I guess it's better idea to use InstallReferrerReceiver.
Just check for some preference with default value indicating that it's a first run. So if you get default value, do your initialization and set this preference to different value to indicate that the app is initialized already.
The following is an example of using SharedPreferences to achieve a 'forWhat' check.
preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferencesEditor = preferences.edit();
public static boolean isFirstRun(String forWhat) {
if (preferences.getBoolean(forWhat, true)) {
preferencesEditor.putBoolean(forWhat, false).commit();
return true;
} else {
return false;
}
}
There's no reliable way to detect first run, as the shared preferences way is not always safe, the user can delete the shared preferences data from the settings!
a better way is to use the answers here Is there a unique Android device ID? to get the device's unique ID and store it somewhere in your server, so whenever the user launches the app you request the server and check if it's there in your database or it is new.
This might help you
public class FirstActivity extends Activity {
SharedPreferences sharedPreferences = null;
Editor editor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
sharedPreferences = getSharedPreferences("com.myAppName", MODE_PRIVATE);
}
#Override
protected void onResume() {
super.onResume();
if (sharedPreferences.getBoolean("firstRun", true)) {
//You can perform anything over here. This will call only first time
editor = sharedPreferences.edit();
editor.putBoolean("firstRun", false)
editor.commit();
}
}
}
SharedPreferences mPrefs;
final String welcomeScreenShownPref = "welcomeScreenShown";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
// second argument is the default to use if the preference can't be found
Boolean welcomeScreenShown = mPrefs.getBoolean(welcomeScreenShownPref, false);
if (!welcomeScreenShown) {
// here you can launch another activity if you like
SharedPreferences.Editor editor = mPrefs.edit();
editor.putBoolean(welcomeScreenShownPref, true);
editor.commit(); // Very important to save the preference
}
}

Clearing all sharedprefs from menu

I have been struggling with implementing a "clear preferences" option in the 3dot (overflow) menu... sample screen shot here:
Coding wise... I tried this but it does not do the job:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.clearsp) {
SharedPreferences preferences = getSharedPreferences("dyna_cb_prf", 0);
preferences.edit().clear().commit();
Intent i = new Intent(Intent.ACTION_VIEW);
startActivity(i);
}
return super.onOptionsItemSelected(item);
Tips on how to modify this? Basically, I want it to clear ALL sharedprefs upon clicking that option (I may have multiple xml files to clear sometimes)
One solution would be to create a SharedPreferencesManager class, that keeps track of all the different SharedPreference xml files, and has a method to clear them all.
Simple example with two types of SharedPreferences:
public class SharedPreferencesManager {
public static SharedPreferences forDynaCpPrf(Context ctx) {
return ctx.getApplicationContext().getSharedPreferences("dyna_cb_prf", 0);
}
public static SharedPreferences forSomethingElse(Context ctx) {
return ctx.getApplicationContext().getSharedPreferences("something_else", 0);
}
public static void clearAllSharedPreferences(Context ctx) {
forDynaCpPrf(ctx).edit().clear().commit();
forSomethingElse(ctx).edit().clear().commit();
}
}
Then, if the user selects the menu item to Clear Preferences, just call the clearAllSharedPreferences() method:
if (id == R.id.clearsp) {
SharedPreferencesManager.clearAllSharedPreferences(this);
}
Note that instead of calling getSharedPreferences("dyna_cb_prf", 0) outside of the SharedPreferencesManager class, you would just call the forDynaCpPrf() method:
SharedPreferences preferences = SharedPreferencesManager.forDynaCpPrf(this);

Calling SharedPreferences from a separate class with a spinner?

I'm not sure how to word this but I'm having issues accessing Shared Preferences under MODE_PRIVATE.
I'm implementing a Spinner like so:
setSessions = (Spinner)findViewById(R.id.numSessions);
setSessions.setOnItemSelectedListener(new CustomOnItemSelectedListener());
The Custom listener is like so:
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;
public class CustomOnItemSelectedListener implements OnItemSelectedListener {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
SharedPreferences defaultPrefs;
defaultPrefs = getSharedPreferences("Defaults", MODE_PRIVATE);
String savedSessions = defaultPrefs.getString("tcpCapSessions", "None Set");
if (savedSessions != parent.getItemAtPosition(pos).toString()) {
final Editor defaultEdit = defaultPrefs.edit();
defaultEdit.putString("tcpCapSessions", parent.getItemAtPosition(pos).toString()); // Writes the key "Default Server" along with Server Name chosen (as the value).
defaultEdit.commit();
}
Toast.makeText(parent.getContext(),
"Sessions set to: " + parent.getItemAtPosition(pos).toString(),
Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
I'm getting an error on the "MODE_PRIVATE" when getting SharedPreferences....
I simply want to update a preference depending on the users selection. I've tried extending the Activity which gets rid of the error but the app will still crash on first launch.
I've checked out Use sharedpreferences inside class but it hasn't helped me resolve the issue, may be it's missing something as it appears like the same issue as myself.
MODE_PRIVATE is a static member of Context. It's actually described pretty good here.
change it to Context.MODE_PRIVATE
Hi Genius try this..
Shared Preferences allow you to save and retrieve data in the form of key,value pair.
You have to call a method getSharedPreferences() that returns a SharedPreferences instance pointing to the file that contains the values of preferences.
SharedPreferences sharedpreferences = getSharedPreferences(YOUR_PREFERENCE_NAME, Context.MODE_PRIVATE);
The first parameter is the Name and the second parameter is the MODE.
Name:
Desired preferences file. If a preferences file by this name does not exist, it will be created when you retrieve an editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
Mode:
(Operating Mode)
0 or MODE_PRIVATE for the default operation.
MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE to control permissions.
MODE_MULTI_PROCESS can also be used if multiple processes are mutating the same SharedPreferences file.
Example:
public class CustomOnItemSelectedListener implements OnItemSelectedListener {
//Initialize SharedPreferences.
public static SharedPreferences.Editor editUserSelection;
public static SharedPreferences prefUserSelection;
public static final String GET_USER_PREF = "get_my_user";
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
//save user selected position.
prefUserSelection = getApplicationContext().getSharedPreferences(GET_USER_PREF, 0);
editUserSelection= prefUserSelection.edit();
editUserSelection.putInt("user", pos);
editUserSelection.commit();
}
For retrieve the user position,
prefUserSelection = getApplicationContext().getSharedPreferences(GET_USER_PREF, 0);
int userSelected = prefUserSelection .getInt("user", 0); //0 is the default value
Toast.makeText(getActivity(), "User Selected Position: "+userSelected ,Toast.LENGTH_SHORT).show();

Android: Title of the action bar disappears

so, in my main activity, on the onCreate() method, I check if it is the app first run with shared preferences... If it is the first run of the app, the user is redirected to a welcome activity, and then, when I press the back button and return to the main activity, the title in the action doesn't show up.. I have tested with api 9 and 17, and this only happens with api 9, so I'm guessing the error must be something about using the support library for the action bar .. Can someone help me ?
Main:
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
public class MainActivity extends ActionBarActivity {
SessionManager session;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// session
session = new SessionManager(getApplicationContext());
// check first time app run
session.checkFirstRun();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
SessionManager First Run check method
// check first run
public void checkFirstRun() {
if(getFirstRunStatus() == true) {
// set first run key as false
editor.putBoolean("FIRST_RUN", false);
editor.commit();
// first time running the app, redirect user to welcome activity
Intent i = new Intent(_context, WelcomeActivity.class);
// Closing all the Activities
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Add new Flag to start new Activity
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
_context.startActivity(i);
}
}
public boolean getFirstRunStatus() {
return pref.getBoolean(FIRST_RUN, true);
}
Add the title in a couple ways:
XML:
<activity
android:name=".....WelcomeActivity"
android:icon="#drawable/logo"
android:label="#string/app_name"
</activity>
On the Fly:
.setTitle("TITLE");
.setIcon(R.drawable.logo);
You can pass the title in an intent to if you want it to be dynamic... not sure if that is what you want:
.setTitle(extras.getString("title"));
Hope that helps.
try this in your onCreateOptionsMenu:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_menu_actions, menu);
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("title");
actionBar .setDisplayShowTitleEnabled(true);
// OR:
// getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME);
return true;
}

Switch Preference - Handling both onPreferenceChange and onPreferenceClick

I've been trying to get a switch preference working in Android whereby I can intercept and handle differently, in certain cases, when they switch it on/off vs when they click the whole preference.
This is what I'm trying to accomplish:
User goes into preferences tags are off and no tags are stored (ie: tag preference is empty)
User turns on preference for tags, and since no tags are stored currently it launches a tag search activity for user to find the tag. - works fine.
If tag already exists, and they change the state ONLY then update the value as normal. - works fine
Here's my issue:
If they click the preference though and they already have a tag saved, don't change the state (regardless if it's enabled or disabled), launch the tag search activity. - this DOESN'T work.
What I've found so far is that in the final scenario above, I get a call to onPreferenceChanged, followed by a call to onPreferenceClicked, followed by a subsequent call to onPreferenceChanged. This seems to be my problem. The first call to onPreferenceChanged causes my listener on my SharedPreferences to be called telling it that it's now enabled.
If I didn't receive the first call to onPreferenceChanged then I wouldn't have an issue.
Here is the relevant parts where I'm setting the listeners
SwitchPreference tagPref = (SwitchPreference) findPreference(PreferencesConstants.PREFERENCE_TAG_ENABLED);
tagPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.e("BLAH", "onPrefChanged....is it handled by OnClick?" + Boolean.toString(handledByClick));
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
boolean enabled = prefs.getBoolean(PreferencesConstants.PREFERENCE_TAG_ENABLED, false);
Log.e("BLAH", "value stored in prefs? " + Boolean.toString(enabled));
if (newValue instanceof Boolean) {
enabled = (Boolean) newValue;
}
Log.e("BLAH", "New value? " + Boolean.toString(enabled));
if (!handledByClick) {
if (enabled && (currentTag == null || currentTag.isEmpty())) {
Log.e("BLAH", "Enabled and CurrentTag empty!");
Intent intent = new Intent(getActivity(), TagSearchActivity.class);
startActivityForResult(intent, 0);
return false; // always return false, we'll handle
// updating
// this value manually.
} else {
return true;
}
}
Log.e("BLAH", "returning false (AS IN WE HANDLED IT).");
return false;
}
});
tagPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
handledByClick = true;
Log.e("BLAH", "onprefClick");
Intent intent = new Intent(getActivity(), TagSearchActivity.class);
startActivityForResult(intent, 0);
return true;
}
});
Here are the relevant log lines after running it with a saved tag, and clicking the preference.
01-18 15:55:05.593: E/BLAH(13261): onPrefChanged....is it handled by OnClick?false
01-18 15:55:05.593: E/BLAH(13261): value stored in prefs? true
01-18 15:55:05.593: E/BLAH(13261): New value? false
01-18 15:55:05.613: E/DifferentClass(13261): On Shared Preferences Changed - tagEnabled
01-18 15:55:05.652: E/DifferentClass(13261): disabled TAG in cancelAlarmService
01-18 15:55:05.662: E/AnotherClass(13261): Updating Feed List. Old Size: 33, New Size: 14
01-18 15:55:05.682: E/BLAH(13261): onprefClick
01-18 15:55:05.812: E/BLAH(13261): onPrefChanged....is it handled by OnClick?true
01-18 15:55:05.812: E/BLAH(13261): value stored in prefs? false
01-18 15:55:05.822: E/BLAH(13261): New value? false
01-18 15:55:05.822: E/BLAH(13261): returning false (AS IN WE HANDLED IT).
I have been working with the same issue for ages now and you can go about it two ways.
Implementing a switchpreference with custom actions for every event:
forevercrashed made some good points. I tried follow them, but for me they didn't do it. I bet they work, but I needed more functionallity in an easier way. Xgouchet (second Link) uses Headers and custom xml layouts which uses custom placements and measurements (height, witdth, padding etc.). I needed a solution without altering Googles built in auto-generated layout.
The super easy and powerful way: implement your own SwitchPreference!
Just make a class extend SwitchPreference and then implement/override like so:
public class AutoUploadSwitchPreference extends SwitchPreference {
public AutoUploadSwitchPreference(Context context) {
super(context);
}
public AutoUploadSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoUploadSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onClick() {
//super.onClick(); THIS IS THE IMPORTANT PART!
}
By overriding onClick() and commenting out / deleting super.onClick() makes the SwitchPreference NOT call callChangeListener(Object newValue). Now you can click the preference and nothing happens, not until you want it to.
(One bug that would occur otherwise was having multiple calls to onPreferenceChange in the fragment)
Now! To make things happen: Here is the structure I have used.
Create a SettingsActivity
In it make sure you fetch preferences, resources etc.
in onCreate() in your Activity - launch a PreferenceFragment
This needs to be a custom class extending PreferenceFragment, see how here : PreferenceFragment
In your custom Fragment, get hold of your custom-preference. You can use findPreference("custom_switch_key").
add an OnPreferenceChangeListener on the preference
I personally make my fragment implement the listener and pass this as argument.
The return statement is important. This is what makes the actual change in the switch. If you return true the switch will change into the newValue. If you return false, it will not. If you use return false; you can change the value with setChecked(true|false) on the switchpreference.
when you implement onPreferenceChange(Preference preference, Object newValue) you can add whatever functionality you want from pressing the switch-slider only
the functionality from clicking the preference can be done in three ways:
Implement the onClick() further in the custom SwitchPreference class
Implement the method onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) in the fragment
Implement an onPreferenceClickListener like you did for the ChangeListener.
Sorry if this is a long post. It is my first and I have been through so many stackoverflow-pages about this and no one was accurate, just wanted to get it right ;)
After searching for hours more I came across a couple posts that will be helpful to others in this situation.
This one was the solution I opted for given my problem: How do I create one Preference with an EditTextPreference and a Togglebutton?
It's a very detailed answer and is very helpful in understanding preferences.
The other post I came across was this one: http://xgouchet.fr/android/index.php?article4/master-on-off-preferences-with-ice-cream-sandwich
It will give you pretty much the same look and feel as the one above, but requires more work and because of my requirements wouldn't work for me.
i think you are asking about a feature that doesn't exist.
however , since the preference activity uses a listView , you can use some tricks to customize it and handle it however you wish .
here's a post i've made about customizing it , based on this website . what i've asked there is how to add a listView , but i didn't know that a preference activity actually uses a listview .
This took me ages, and none of the answers here worked. I finally found the simplest answer, no custom layout required, in a Github Gist, which I'll preserve here, but I have modified it to work with SwitchPreferenceCompat instead of SwitchPreference.
First, create the custom preference.
package com.mendhak.gpslogger.ui.components;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.widget.SwitchCompat;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreferenceCompat;
/**
* Custom preference for handling a switch with a clickable preference area as well
*/
public class SwitchPlusClickPreference extends SwitchPreferenceCompat {
//
// Public interface
//
/**
* Sets listeners for the switch and the background container preference view cell
* #param listener A valid SwitchPlusClickListener
*/
public void setSwitchClickListener(SwitchPlusClickListener listener){
this.listener = listener;
}
private SwitchPlusClickListener listener = null;
/**
* Interface gives callbacks in to both parts of the preference
*/
public interface SwitchPlusClickListener {
/**
* Called when the switch is switched
* #param buttonView
* #param isChecked
*/
public void onCheckedChanged(SwitchCompat buttonView, boolean isChecked);
/**
* Called when the preference view is clicked
* #param view
*/
public void onClick(View view);
}
public SwitchPlusClickPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SwitchPlusClickPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwitchPlusClickPreference(Context context) {
super(context);
}
//
// Internal Functions
//
/**
* Recursively go through view tree until we find an android.widget.Switch
* #param view Root view to start searching
* #return A Switch class or null
*/
private SwitchCompat findSwitchWidget(View view){
if (view instanceof SwitchCompat){
return (SwitchCompat)view;
}
if (view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount();i++){
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup){
SwitchCompat result = findSwitchWidget(child);
if (result!=null) return result;
}
if (child instanceof SwitchCompat){
return (SwitchCompat)child;
}
}
}
return null;
}
#Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final SwitchCompat switchView = findSwitchWidget(holder.itemView);
if (switchView!=null){
switchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onCheckedChanged((SwitchCompat) v, ((SwitchCompat)v).isChecked());
}
});
switchView.setChecked(getSharedPreferences().getBoolean(getKey(),false));
switchView.setFocusable(true);
switchView.setEnabled(true);
//Set the thumb drawable here if you need to. Seems like this code makes it not respect thumb_drawable in the xml.
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onClick(v);
}
});
}
// //Get a handle on the 2 parts of the switch preference and assign handlers to them
// #Override
// protected void onBindView (View view){
// super.onBindView(view);
//
// final Switch switchView = findSwitchWidget(view);
// if (switchView!=null){
// switchView.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// if (listener != null)
// listener.onCheckedChanged((Switch) v, ((Switch)v).isChecked());
// }
// });
// switchView.setChecked(getSharedPreferences().getBoolean(getKey(),false));
// switchView.setFocusable(true);
// switchView.setEnabled(true);
// //Set the thumb drawable here if you need to. Seems like this code makes it not respect thumb_drawable in the xml.
// }
//
// view.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// if (listener!=null) listener.onClick(v);
// }
// });
// }
}
Next in your preference XML, add an entry:
<com.mendhak.gpslogger.ui.components.SwitchPlusClickPreference
android:key="google_drive_enabled"
android:title="#string/google_drive_setup_title"
android:icon="#drawable/googledrive"/>
And then in the code for your Preference Activity class, the real magic is that you use the built-in callbacks for changed, and clicked.
((SwitchPlusClickPreference)findPreference(PreferenceNames.AUTOSEND_GOOGLE_DRIVE_ENABLED)).setSwitchClickListener(new SwitchPlusClickPreference.SwitchPlusClickListener() {
#Override
public void onCheckedChanged(SwitchCompat buttonView, boolean isChecked) {
//The switch bit changed. handle it.
}
#Override
public void onClick(View view) {
// The text bit was clicked on, handle it
}
});

Categories

Resources