Skip to content

Instantly share code, notes, and snippets.

@Sroka
Last active January 15, 2017 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sroka/df4a56cd8c692e6f5541e5a691792806 to your computer and use it in GitHub Desktop.
Save Sroka/df4a56cd8c692e6f5541e5a691792806 to your computer and use it in GitHub Desktop.
package com.example;
import android.os.Build;
import android.view.View;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by srokowski.maciej@gmail.com on 16.11.16.
*/
public class ViewIdGenerator {
/**
* Unique view id generator, like the one used in {@link View} class for view id generation.
* Since we can't access the generator within the {@link View} class before API 17, we create
* the same generator here. This creates a problem of two generator instances not knowing about
* each other, and we need to take care that one does not generate the id already generated by other one.
* <p>
* We know that all integers higher than 16 777 215 are reserved for aapt-generated identifiers
* (source: {@link View#generateViewId()}, so we make sure to never generate a value that big.
* We also know that generator within the {@link View} class starts at 1.
* We set our generator to start counting at 15 000 000. This gives us enough space
* (15 000 000 - 16 777 215), while making sure that generated IDs are unique, unless ILocationChooserView generates
* more than 15M IDs, which should never happen.
*/
private static final AtomicInteger viewIdGenerator = new AtomicInteger(15000000);
/**
* Generate a value suitable for use in {@link View#setId(int)}.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
* @return a generated ID value
*/
public static int generateViewId() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return generateUniqueViewId();
} else {
return View.generateViewId();
}
}
private static int generateUniqueViewId() {
while (true) {
final int result = viewIdGenerator.get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
if (viewIdGenerator.compareAndSet(result, newValue)) {
return result;
}
}
}
}
package com.example;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.HashMap;
/**
* Created by srokowski.maciej@gmail.com on 16.11.16.
*/
public class ViewIdRestorer {
private static final String TAG_ID_MAP_KEY = "TAG_ID_MAP_KEY";
private HashMap<String, Integer> tagIdMap = new HashMap<>();
public int getId(String tag) {
if (tagIdMap.containsKey(tag)) {
return tagIdMap.get(tag);
} else {
final int viewId = ViewIdGenerator.generateViewId();
tagIdMap.put(tag, viewId);
return viewId;
}
}
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
final HashMap<String, Integer> savedTagIdMap = (HashMap<String, Integer>) savedInstanceState.getSerializable(TAG_ID_MAP_KEY);
tagIdMap.putAll(savedTagIdMap);
}
}
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
final HashMap<String, Integer> savedTagIdMap = (HashMap<String, Integer>) savedInstanceState.getSerializable(TAG_ID_MAP_KEY);
tagIdMap.putAll(savedTagIdMap);
}
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putSerializable(TAG_ID_MAP_KEY, tagIdMap);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment