下面列出了怎么用android.support.annotation.AnyThread的API类实例代码及写法,或者点击链接到github查看源代码。
@AnyThread
private void playMusic() {
if (messageClient != null) {
bindService();
messageClient.sendToTarget(EventCode.CODE_PLAY_MUSIC);
messageClient.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (vibrator != null) {
vibrator.cancel();
}
vibrator = (Vibrator) messageClient.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
long[] patter = {500, 3000, 500, 3000};
assert vibrator != null;
vibrator.vibrate(patter, 0);
}
});
}
}
@AnyThread
public void update() {
executorService.execute(new Runnable() {
@Override
public void run() {
LitePal.where("status=?", "0").findAsync(TaskDao.class)
.listen(new FindMultiCallback<TaskDao>() {
@Override
public void onFinish(final List<TaskDao> list) {
recyclerView.post(new Runnable() {
@Override
public void run() {
update(list);
}
});
}
});
}
});
}
@AnyThread
private void createTimer() {
if (currentTask == null) {
return;
}
long nowTime = System.currentTimeMillis();
long interval = currentTask.getKillTime() - nowTime;
// 任务结束
if (interval <= -1000) {
currentTask = null;
if (timerPair != null) {
timerPair.first.cancel();
}
Log.i(TAG, "任务结束");
return;
}
if (interval > 5 * 60 * 1000) {
createTimeTask(60_000);
} else if (interval > 60 * 1000) {
createTimeTask(30_000);
} else if (interval > 5 * 1000) {
createTimeTask(3000);
} else {
createTimeTask(MIN_INTERVAL);
}
}
@AnyThread
@NonNull
@VisibleForTesting
AuthState readState() {
mPrefsLock.lock();
try {
String currentState = mPrefs.getString(KEY_STATE, null);
if (currentState == null) {
return new AuthState();
}
try {
return AuthState.jsonDeserialize(currentState);
} catch (JSONException ex) {
Log.w(TAG, "Failed to deserialize stored auth state - discarding");
return new AuthState();
}
} finally {
mPrefsLock.unlock();
}
}
@AnyThread
@VisibleForTesting
void writeState(@Nullable AuthState state) {
mPrefsLock.lock();
try {
SharedPreferences.Editor editor = mPrefs.edit();
if (state == null) {
editor.remove(KEY_STATE);
} else {
editor.putString(KEY_STATE, state.jsonSerializeString());
}
if (!editor.commit()) {
throw new IllegalStateException("Failed to write state to shared prefs");
}
} finally {
mPrefsLock.unlock();
}
}
/**
* Initializes the OktaAppAuth object. This will fetch an OpenID Connect discovery document
* from the issuer in the configuration to configure this instance for use.
*
* @param context The application context
* @param listener An OktaAuthListener that will be called once the initialization is
* complete
* @param customTabColor The color that will be passed to
* {@link CustomTabsIntent.Builder#setToolbarColor(int)}
* @param oktaConnectionBuilder Implementation of {@link OktaConnectionBuilder}
*/
@AnyThread
public void init(
final Context context,
final OktaAuthListener listener,
@ColorInt int customTabColor,
final OktaConnectionBuilder oktaConnectionBuilder) {
mCustomTabColor = customTabColor;
mConnectionBuilder = new ConnectionBuilder() {
@NonNull
@Override
public HttpURLConnection openConnection(@NonNull Uri uri) throws IOException {
return oktaConnectionBuilder.openConnection(uri);
}
};
mExecutor.submit(new Runnable() {
@Override
public void run() {
doInit(context, mConnectionBuilder, listener);
}
});
}
/**
* Set the color stops used for the heat map's gradient. There needs to be at least 2 stops
* and there should be one at a position of 0 and one at a position of 1.
* @param stops A map from stop positions (as fractions of the width in [0,1]) to ARGB colors.
*/
@AnyThread
public void setColorStops(Map<Float, Integer> stops) {
if (stops.size() < 2)
throw new IllegalArgumentException("There must be at least 2 color stops");
colors = new int[stops.size()];
positions = new float[stops.size()];
int i = 0;
for (Float key : stops.keySet()) {
colors[i] = stops.get(key);
positions[i] = key;
i++;
}
if (!mTransparentBackground)
mBackground.setColor(colors[0]);
}
@AnyThread
@SuppressWarnings("WrongThread")
private float getScale() {
if (mMaxWidth == null || mMaxHeight == null)
return 1.0f;
float sourceRatio = getWidth() / getHeight();
float targetRatio = mMaxWidth / mMaxHeight;
float scale;
if (sourceRatio < targetRatio) {
scale = getWidth() / ((float)mMaxWidth);
}
else {
scale = getHeight() / ((float)mMaxHeight);
}
return scale;
}
@AnyThread
@SuppressLint("WrongThread")
private void redrawShadow(int width, int height) {
mRenderBoundaries[0] = 10000;
mRenderBoundaries[1] = 10000;
mRenderBoundaries[2] = 0;
mRenderBoundaries[3] = 0;
if (mUseDrawingCache)
mShadow = getDrawingCache();
else
mShadow = Bitmap.createBitmap(getDrawingWidth(), getDrawingHeight(), Bitmap.Config.ARGB_8888);
Canvas shadowCanvas = new Canvas(mShadow);
drawTransparent(shadowCanvas, width, height);
}
/**
* 抢票成功
*/
@AnyThread
private void ticketSuccess(@NonNull Trains trains) {
isStarted.set(false);
playMusic();
messageClient.sendToTarget(EventCode.CODE_TICKET_SUCCESS);
MessageUtil.sendToHi(trains);
}
@AnyThread
public void runJs(final String js) {
final Page page = getTopPage();
if (page == null) {
Log.w(TAG, "page is Null");
return;
}
final XWebView webView = page.getWebView();
if (webView != null) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
webView.evaluateJavascriptWithException(js, null);
} catch (Exception e) {
Log.e(TAG, "evaluateJavascriptWithException", e);
if (e instanceof InvocationTargetException) {
Throwable target = ((InvocationTargetException) e).getTargetException();
if (target != null && target.getMessage() != null
&& target.getMessage().contains("WebView had destroyed")) {
Log.i(TAG, "pop webView: " + webView.hashCode());
page.popWebView();
}
}
}
}
};
if (Looper.getMainLooper() != Looper.myLooper()) {
page.getActivity().runOnUiThread(runnable);
} else {
runnable.run();
}
Log.i(TAG, "webView:" + webView.hashCode() + ", queryJs: " + js);
} else {
Log.w(TAG, "getWebView is Null, page=" + page.hashCode() + ", pageSize=" + pages.size()
+ ", activity=" + page.getActivity().getClass());
}
}
@AnyThread
private synchronized void createTimeTask(long waitTime) {
if (timerPair != null) {
if (timerPair.second == waitTime) {
Log.i(TAG, "相同等待时间:" + waitTime);
return;
}
timerPair.first.cancel();
}
Timer timer = new Timer();
timerPair = Pair.create(timer, waitTime);
timer.schedule(new TimerTask() {
@Override
public void run() {
if (currentTask != null) {
// 500ms - 900ms 触发4次
int interval = (int) (currentTask.killTime - System.currentTimeMillis());
int millisecond = interval / 100;
if (millisecond >= 1 && millisecond <= 4) {
currentTask.run();
}
}
createTimer();
}
}, 0, waitTime);
Log.i(TAG, "Timer:" + waitTime);
}
/**
* Helper method for load tasks. Examines the EXIF info on the image file to determine the orientation.
* This will only work for external files, not assets, resources or other URIs.
*/
@AnyThread
private int getExifOrientation(Context context, String sourceUri) {
int exifOrientation = ORIENTATION_0;
Cursor cursor = null;
try {
String[] columns = { MediaStore.Images.Media.ORIENTATION };
cursor = context.getContentResolver().query(Uri.parse(sourceUri), columns, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
int orientation = cursor.getInt(0);
if (VALID_ORIENTATIONS.contains(orientation) && orientation != ORIENTATION_USE_EXIF) {
exifOrientation = orientation;
} else {
Log.w(TAG, "Unsupported orientation: " + orientation);
}
}
}
} catch (Exception e) {
Log.w(TAG, "Could not get orientation of image from media store");
} finally {
if (cursor != null) {
cursor.close();
}
}
return exifOrientation;
}
/**
* Converts source rectangle from tile, which treats the image file as if it were in the correct orientation already,
* to the rectangle of the image that needs to be loaded.
*/
@SuppressWarnings("SuspiciousNameCombination")
@AnyThread
private void fileSRect(Rect sRect, Rect target) {
if (getRequiredRotation() == 0) {
target.set(sRect);
} else if (getRequiredRotation() == 90) {
target.set(sRect.top, sHeight - sRect.right, sRect.bottom, sHeight - sRect.left);
} else if (getRequiredRotation() == 180) {
target.set(sWidth - sRect.right, sHeight - sRect.bottom, sWidth - sRect.left, sHeight - sRect.top);
} else {
target.set(sWidth - sRect.bottom, sRect.left, sWidth - sRect.top, sRect.right);
}
}
/**
* Determines the rotation to be applied to tiles, based on EXIF orientation or chosen setting.
*/
@AnyThread
private int getRequiredRotation() {
if (orientation == ORIENTATION_USE_EXIF) {
return sOrientation;
} else {
return orientation;
}
}
/**
* Debug logger
*/
@AnyThread
private void debug(String message, Object... args) {
if (debug) {
Log.d(TAG, String.format(message, args));
}
}
/**
* Converts source rectangle from tile, which treats the image file as if it were in the correct orientation
* already,
* to the rectangle of the image that needs to be loaded.
*/
@SuppressWarnings("SuspiciousNameCombination") @AnyThread
private void fileSRect(Rect sRect, Rect target) {
if (getRequiredRotation() == 0) {
target.set(sRect);
} else if (getRequiredRotation() == 90) {
target.set(sRect.top, sHeight - sRect.right, sRect.bottom, sHeight - sRect.left);
} else if (getRequiredRotation() == 180) {
target.set(sWidth - sRect.right, sHeight - sRect.bottom, sWidth - sRect.left, sHeight - sRect.top);
} else {
target.set(sWidth - sRect.bottom, sRect.left, sWidth - sRect.top, sRect.right);
}
}
/**
* Determines the rotation to be applied to tiles, based on EXIF orientation or chosen setting.
*/
@AnyThread
private int getRequiredRotation() {
if (orientation == ORIENTATION_USE_EXIF) {
return sOrientation;
} else {
return orientation;
}
}
/**
* Debug logger
*/
@AnyThread
private void debug(String message, Object... args) {
if (debug) {
Log.d(TAG, String.format(message, args));
}
}
/**
* Converts source rectangle from tile, which treats the image file as if it were in the correct orientation already,
* to the rectangle of the image that needs to be loaded.
*/
@SuppressWarnings("SuspiciousNameCombination")
@AnyThread
private void fileSRect(Rect sRect, Rect target) {
if (getRequiredRotation() == 0) {
target.set(sRect);
} else if (getRequiredRotation() == 90) {
target.set(sRect.top, sHeight - sRect.right, sRect.bottom, sHeight - sRect.left);
} else if (getRequiredRotation() == 180) {
target.set(sWidth - sRect.right, sHeight - sRect.bottom, sWidth - sRect.left, sHeight - sRect.top);
} else {
target.set(sWidth - sRect.bottom, sRect.left, sWidth - sRect.top, sRect.right);
}
}
/**
* Determines the rotation to be applied to tiles, based on EXIF orientation or chosen setting.
*/
@AnyThread
private int getRequiredRotation() {
if (orientation == ORIENTATION_USE_EXIF) {
return sOrientation;
} else {
return orientation;
}
}
/**
* Debug logger
*/
@AnyThread
private void debug(String message, Object... args) {
if (debug) {
Log.d(TAG, String.format(message, args));
}
}
/**
* Converts source rectangle from tile, which treats the image file as if it were in the correct orientation already,
* to the rectangle of the image that needs to be loaded.
*/
@SuppressWarnings("SuspiciousNameCombination")
@AnyThread
private void fileSRect(Rect sRect, Rect target) {
if (getRequiredRotation() == 0) {
target.set(sRect);
} else if (getRequiredRotation() == 90) {
target.set(sRect.top, sHeight - sRect.right, sRect.bottom, sHeight - sRect.left);
} else if (getRequiredRotation() == 180) {
target.set(sWidth - sRect.right, sHeight - sRect.bottom, sWidth - sRect.left, sHeight - sRect.top);
} else {
target.set(sWidth - sRect.bottom, sRect.left, sWidth - sRect.top, sRect.right);
}
}
/**
* Determines the rotation to be applied to tiles, based on EXIF orientation or chosen setting.
*/
@AnyThread
private int getRequiredRotation() {
if (orientation == ORIENTATION_USE_EXIF) {
return sOrientation;
} else {
return orientation;
}
}
/**
* Debug logger
*/
@AnyThread
private void debug(String message, Object... args) {
if (debug) {
Log.d(TAG, String.format(message, args));
}
}
@AnyThread
@Override
public void goToLogin() {
runOnUiThread(() -> {
startActivity(new Intent(this, LoginActivity.class));
finish();
});
}
@AnyThread
@Override
public void goToMain() {
runOnUiThread(() -> {
startActivity(new Intent(this, MainActivity.class));
finish();
});
}
/**
* Retrieve the manager object via the static {@link WeakReference} or construct a new instance.
* Stores the state in the {@link SharedPreferences} that we get from the
* {@link Context#getSharedPreferences(String, int)} in {@link Context#MODE_PRIVATE}.
*
* @param context The Context from which to get the application's environment
* @return an AuthStateManager object
*/
@AnyThread
public static AuthStateManager getInstance(@NonNull Context context) {
AuthStateManager manager = INSTANCE_REF.get().get();
if (manager == null) {
manager = new AuthStateManager(
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE),
new ReentrantLock()
);
}
return manager;
}
/**
* Returns the current AuthState stored in the {@link SharedPreferences}.
*
* @return the stored AuthState
*/
@AnyThread
@NonNull
public AuthState getCurrent() {
if (mCurrentAuthState.get() != null) {
return mCurrentAuthState.get();
}
AuthState state = readState();
if (mCurrentAuthState.compareAndSet(null, state)) {
return state;
} else {
return mCurrentAuthState.get();
}
}
/**
* Replaces the current AuthState in {@link SharedPreferences} with the provided once.
*
* @param state The updated AuthState
* @return The AuthState which was stored in the SharedPreferences
*/
@AnyThread
@NonNull
public AuthState replace(@NonNull AuthState state) {
writeState(state);
mCurrentAuthState.set(state);
return state;
}