MaterialDrawer set selected profile - java

I use the MaterialDrawer library by Mike Penz.
In my OnCreate, profiles are added to the drawer from a linkedHashMap. When a profile gets selected, the new selected profile is saved in a sharedPreference.
My Question: if I launch the App again, how can I set the profile, whichs name is stored in the sharedPreference, as the selected?
Edit: Without an identifier? Or is this not possible?

The MaterialDrawer requires an identifier given to it's elements so that you can reselect them (and that the Drawer itself can re-select them upon configuration changes) again.
Simply provide any id. You can use something like this:
private static long hashString64Bit(CharSequence str) {
long result = 0xcbf29ce484222325L;
final int len = str.length();
for (int i = 0; i < len; i++) {
result ^= str.charAt(i);
result *= 0x100000001b3L;
}
return result;
}
To generate an long identifier for your string, or you generate some kind of hashcode.

Related

Java - dynamically build textview reference

New Android/Java coder. Trying to replicate in Android app a project I built in MS-Access.
I have a layout with similar named TextViews, like text10, text12, etc. In MS-Access I can dynamically build those names with collection referencing:
For X = 10 To 15
Me.Controls("text" & X) = Null
Next
There is no array required. So looking for structure in java that can accomplish the same functionality.
I want to dynamically set background color of multiple TextView based on two inputs. One is to build TextView reference and the other is a state indicator that will determine color.
Here is one procedure calling setSubColor:
public void Clear(MenuItem mi) {
puz.setText("");
sol.setText("");
for (int i=0; i<26; i++) {
setSubColor(aryA[i].charAt(0), 0);
What I have so far for setSubColor:
public void setSubColor (char c, int i) {
TextView v = (TextView) >>>dynamically reference v using name built with ("tv" + c)
if (i == 0) {v.setBackgroundColor(Color.TRANSPARENT);}
else {v.setBackgroundColor(Color.YELLOW);}
You can get the res id from the res name at runtime. So if your textview had name "text1", you could get the integer id by using:
int id = getResources().getIdentifier("text1", "string", getPackageName());
TextView view = findViewById(id);
But do so only as a last resort, it's error prone, slow and somewhat of an anti pattern.
EDIT by OP: No matter what the name argument is always returns 0 but marked as answer because it led to the following code that works exactly as I want, anti-pattern or not.
TextView v = (TextView) findViewById(getResources().getIdentifier("tv" + c, "id", getPackageName()));
Instead of the TextView Id field use its Tag field.
String tag = (String)textView.getTag() and textView.setTag(Object tag) with tag instanceof String
then you can find the TextView by Tag

finding the value pair that has the highest affinity in Java?

Hi I am current working on a algorithm problem set.
Given the below file in a file.txt file,
yahoo,ap42
google,ap42
twitter,thl76
google,aa314
google,aa314
google,thl76
twitter,aa314
twitter,ap42
yahoo,aa314
A web server logs page views in a log file. The log file consists of one line per page view. A page view consists of page id and a user id, separated by a comma. The affinity of a pair of pages is the number of distinct users who viewed both pages. For example in the quoted log file, the affinity of yahoo and google is 2 (because ap42 viewed both and aa314 viewed both).
My requirement is to create an algorithm which will return the pair of pages with highest affinity.
Currently, I have written below code, however, right now it is not returning the pair of pages with highest affinity, any suggest of how I am modify the code to make it work? thanks. :
Scanner in = new Scanner(new File("./file.txt"));
ArrayList<String[]> logList = new ArrayList<String[]>();
while (in.hasNextLine()) {
logList.add(in.nextLine().split(","));
}
String currentPage;
String currentUser;
int highestCount =0;
for (int i = 0; i < logList.size()-1; i++) {
int affinityCount =0;
currentPage = logList.get(i)[0];
currentUser = logList.get(i)[1];
for (int j = logList.size()-1; j > 0; j--) {
if (i != j) {
if (!currentPage.equals(logList.get(j)[0])
&& currentUser.equals(logList.get(j)[1])) {
affinityCount++;
System.out.println("currentPage: "+currentPage+" currentUser: "+ currentUser);
System.out.println("logList.get(j)[0]: "+logList.get(j)[0]+" logList.get(j)[1]): "+ logList.get(j)[1]);
System.out.println(affinityCount);
}
}
}
}
Am going to write the algorithm here . You can convert that into the code.
Traverse the file and create a hashMap of .
After this traversal, you shall get the pages viewed by each user.
Now traverse this dataset. For each user, take out the list of pages he viewed. Make all possible combinations of pair of pages and put it in a max heap with value set to 1. If the combination exists in heap, increment the value.
Make sure you treat - yahoo,google same as google,yahoo while comparing.
At the end of this, the element at top of the heap is your output.

ImageView setBackround inside the activity dynamically

Inside my drawabale folder I have these images: levelone, leveltwo, level three.
i need to set the ImageView according to the inputted string as follows:
levelindicatorImageView = (ImageView) findViewById(R.id.levelindicatorImageView);
String tempo="R.drawable.level"+LevelReached;
Drawable replacer = getResources().getDrawable(tempo);
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
levelindicatorImageView.setBackgroundDrawable(replacer);
} else {
levelindicatorImageView.setBackground(replacer);
}
levelindicatorImageView.invalidate();
now inside LevelReached variable i have the needed level (one, two, three)
I need to set the Image R.drawable.leveltwo etc...
How is that possible please?
as getDrawable doesn't work with tempo (needs int)
thanks for the help!
You have 2 options:
Option 1:
Simply use a switch-case to get the correct drawable, then set it as a background image as you normally would
// Get the level drawable resource id
int imageRes = R.drawable.default_image;
switch (levelReached) {
case LEVEL_ONE: // 1
imageRes = R.drawable.level_one;
break;
case LEVEL_TWO: // 2
imageRes = R.drawable.level_two;
break;
...
}
// Set the drawable as a background
levelIndicatorImageView.setBackgroundResource(imageRes);
Where LEVEL_ONE == 1; LEVEL_TWO == 2; as const or enum.
Option 2:
You can find a drawable resource by name (as you wanted), but it is less recommended since it is more error prune. But if you must, use following example:
// Get the level drawable resource id
int imageRes = getResources().getIdentifier("level"+levelReached, "drawable", getPackageName());
// Set the drawable as a background
levelIndicatorImageView.setBackgroundResource(imageRes);
Note:
You don't need to explicitly invalidate the view if you set the background since setting a new background will trigger invalidation by itself. So, this line:
levelindicatorImageView.invalidate();
is not needed.
You cant append input string to image name, but what you can do is,
select the image based on input string and then If you have 3 different images, try with ;
if(input.equalsIgnoreCase("input one"))
{
int id = R.drawable.<img one>;
}
else
{
//so on
}
levelindicatorImageView.setBackground(getResources().getDrawable( id) );
You need to do something like this:
public int getResourecId(String level) {
if(level.equalsIgnoreCase("one"))
return R.drawable.levelone;
if(level.equalsIgnoreCase("two"))
return R.drawable.leveltwo;
if(level.equalsIgnoreCase("three"))
return R.drawable.levelthree;
return 0;
}
and then:
Drawable replacer = getResources().getDrawable(getResourceId(LevelReached));
You need to associate the levels to a resource, in this case, an int. An idiomatic way of doing this would be to store the levels as an enum, say
enum Level { ONE, TWO, THREE }
Using an enum in this way allows you some flexibility with your level conventions. For example, if you later wanted to add the level TWO_THIRDS, there is nothing stoping you. Then, associate each level with a resource in an EnumMap, for example:
Map<Level, Integer> levelResources = new EnumMap<Level, Integer>(Level.class);
levelResources.put(ONE, R.drawable.levelOne);
levelResources.put(TWO, R.drawable.levelTwo);
levelResources.put(THREE, R.drawable.levelThree);
Now, instead of passing around a string which describes your current level, you can pass around an enum, which you can use to determine the correct resource without concatenating strings. So, suppose that levelReached is of type Level, you could write:
Integer tempo = levelResources.get(levelReached);
Drawable replacer = getResources().getDrawable(tempo);

Iterating through two arrays, having trouble with indices

I have a question about creating dynamic arrays and iterating through these arrays. I have a method setVoltage that takes as parameters a string and a double value. I needed some way to store these values so I created two arrays. What i need to do is iterate through the String array to see if the string parameter already exists and if it does, to set the corresponding voltage at that index. If it doesn't exist, i need to add the string device to the string array and also add the double voltage to the double array. Can someone check out my code and see what I am missing? I'm running into trouble because I want the array to realize the string is already in the array, or append it to the end of the array but I'm stuck on how to use index variables to achieve this. Thank you!
public final int sizeArray = 10;
private String[] deviceList = new String[sizeArray];
public double[] voltList = new double[sizeArray];
public synchronized void setVoltage(String device, double voltage) {
int index = 0;
for(int i = 0; i < deviceList.length; i++ ){
//if the device name already exists in the device array, overwrite voltage at that index
if(this.deviceList[i].equals(device)){
index = i;
voltList[index] = voltage;
}else{
//set deviceList[i] equal to device, set voltList[i] equal to voltage
deviceList[i] = device;
voltList[i] = voltage;
index++;
}
}
}
It sounds like perhaps you want a Map<String,Double> instead. This will let you store voltage values keyed by device name, and you can easily find, insert, and remove devices. See, for example, HashMap:
Map<String,Double> deviceVoltages = new HashMap<String,Double>();
deviceVoltages.put("liquifier", 8.4);
deviceVoltages.put("reflarbulator", 900.0);
deviceVoltages.put("liquifier", 13.3); // replaces previous 8.4
System.out.println(deviceVoltages.get("liquifier"));
deviceVoltages.remove("reflarbulator");
Your example code then reduces to simply:
private Map<String,Double> deviceVoltages = new HashMap<String,Double>();
public synchronized void setVoltage(String device, double voltage) {
deviceVoltages.put(device, voltage);
}
Performance will exceed that of your array, and you will not have a hard-coded limit on number of devices.
See generic Map documentation for links to other types of maps in the JDK.
See also ConcurrentHashMap if a finer synchronization granularity is desired and/or acceptable.
An alternative, if you must use arrays, is to create a Device class that encapsulates all the relevant information about a device and use a single array to simplify your logic, e.g.:
static class Device {
String name;
double voltage;
}
Device[] devices = new Device[10];
You can add new devices by replacing a null element in the array. You can update devices by finding the one with the specified name and changing its voltage field. You can optionally use a List<Device> to avoid hard-coded size limits.
It would be way better to use a Map<String,Double> in this scenario. But if you still want to use two arrays, your current code is not appending to the end of the array. Say if i=0 and deviceList[i] != device , then your code immediately overwrites deviceList[i] with the new value in the else block rather than appending it to the end of the array. To append, you have to move the code in the else part to after the for loop.
Your code will always overwrite the device if the device name was not found. It would be better if you used a Map but if you are required to use arrays you can try the following
for(int i = 0; i < deviceList.length; i++ ){
//if the device name already exists in the device array, overwrite voltage at that index
if(this.deviceList[i].equals(device)){
voltList[i] = voltage;
break;
}else if (deviceList[i] == null) {
//set deviceList[i] equal to device, set voltList[i] equal to voltage
deviceList[i] = device;
voltList[i] = voltage;
break;
}
}
You'll have to write some additional code to deal with a full array.
This is how I would do it as-is:
public void setOrAppend(String device, double voltage) {
int index = 0;
for ( ; index < deviceList.length; i++) {
if (device.equals(deviceList[index]) || deviceList[index] == null) {
break;
}
}
if (index == deviceList.length) {
deviceList = Arrays.copyOf(deviceList, deviceList.length + 1);
voltList = Arrays.copyOf(voltList, voltList.length + 1);
}
deviceList[index] = device;
voltList[index] = voltage;
}
I would recommend doing the set logic outside the loop. Additionally I would also recommend a Map for this kind of scenario since this kind of logic is simpler. A Map will already do what you are asking automatically (replace if exists otherwise append).

Android SharedPreferences auto incrementing technique

I wanted some feedback on this approach. My apologies if this is confusing or nonsensical. (thats probably why I'm asking because im unsure.)
My app auto assigns clientID's to a textview at first launch - is auto set to 100. To do this from that point forward I store an int value to sharedpreferences. At Oncreate I run a check against this specific ID in the sharedpreferences and later it either increments or assigns back to 100. The challenge was that sharedpreferences (that I know of) can only take a string value i.e. (editor.putString("CLIENTID", ID);) or editor.putInt("ID", c);
I wanted to avoid using a database for this portion to minimize overhead (could be wrong) There are validations in place that prevent this from being incremented unless certain conditions are met.
c is my persisted counter used in the shared preferences.
Here's what I did at oncreate:
public String ID; //global
int checkCount = prefs.getInt("ID", c); //get the current ID value currently set or last set.
if( checkCount > 100)
{
c = checkCount; //whatever the value of c is from its latest increment the counter c set to this
}
else if (checkCount <= 100)
{
c = 100; //base value of clientIDs //assign base value for starting clientIDs
}
ID = "" + c + ""; //sets value of the counter to a string
//Parsing integer was not passing correctly.
clientID.setText(ID);
In the onclick:
//Once all the conditions are met pass the clientID for this instance.
SharedPreferences.Editor editor = prefs.edit(); //USING EDITOR TO ADD TO THE PREFERENCES
editor.putInt("ID", c);
....// then other stuff.
Any thoughts? My apologies if this is a noob question. I just want to be sure about this approach if this app goes all the way.
Thanks

Categories