Java 信号量阻塞线程,但不会释放它
基本上,这里的想法是等待服务器发送访问令牌,否则资源将加载旧令牌,应用程序将崩溃。但在Java 信号量阻塞线程,但不会释放它,java,android,concurrency,semaphore,Java,Android,Concurrency,Semaphore,基本上,这里的想法是等待服务器发送访问令牌,否则资源将加载旧令牌,应用程序将崩溃。但在getAccessToken()异步请求中获取令牌,并使用waitUntiAccessTokenIstained.release()释放许可证后,主线程保持阻塞状态WaitUntiAccessTokenIsTained.acquire()放在MainActivity的onCreate方法中。我错过了什么 public class MainActivity extends AppCompatActivity {
getAccessToken()
异步请求中获取令牌,并使用waitUntiAccessTokenIstained.release()
释放许可证后,主线程保持阻塞状态WaitUntiAccessTokenIsTained.acquire()
放在MainActivity
的onCreate
方法中。我错过了什么
public class MainActivity extends AppCompatActivity {
private BottomNavigationView bottomNavigationView;
private final String IS_FIRST_USE_FLAG = "IS_FIRST_USE_FLAG";
Semaphore waitUntiAccessTokenIsObtained = new Semaphore(0);
private static boolean isFirstUseFlagValue;
SharedPreferences prefs;
ClientCredentialsStore credentialsStore;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefs = this.getSharedPreferences("com.myapp", Context.MODE_PRIVATE);
handleFlags();
if(this.isFirstUseFlagValue){
registerClient();
getAccessToken();
try {
waitUntiAccessTokenIsObtained.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setContentView(R.layout.main_screen);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.navigation);
bottomNavigationView
.setOnNavigationItemSelectedListener
(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.action_item1:
selectedFragment = HomeFragment.newInstance();
break;
case R.id.action_item2:
selectedFragment = CathegoriesListFragment.newInstance();
break;
case R.id.action_item3:
selectedFragment = TestFragment.newInstance();
break;
case R.id.action_item4:
selectedFragment = ItemThreeFragment.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, HomeFragment.newInstance());
transaction.commit();
//Used to select an item programmatically
//bottomNavigationView.getMenu().getItem(1).setChecked(true);
}
private void handleFlags(){
this.isFirstUseFlagValue = prefs.getBoolean(this.IS_FIRST_USE_FLAG, true);
}
private void registerClient(){
// TODO client registration on server.
String clientNameValue = "clientId";
String clientPasswordValue ="clientSecret";
credentialsStore = new ClientCredentialsStore(getApplicationContext());
credentialsStore.save(clientNameValue, clientPasswordValue);
}
private void getAccessToken(){
// Obtain token from the server.
ClientCredentialsStore credentialsStore = new ClientCredentialsStore(getApplicationContext());
ClientCredentials credentials = credentialsStore.getCredentials();
Call<AccessToken> call = ClientAPI.oAuth2ClientCredentialsGrant(credentials).tokenClient(
ClientAccessTokenRequest.from());
call.enqueue(new Callback<AccessToken>() {
@Override
public void onResponse(Call<AccessToken> call, retrofit2.Response<AccessToken> response) {
AccessToken accessToken = response.body();
TokenStore store = new TokenStore(getApplicationContext());
store.save(accessToken);
waitUntiAccessTokenIsObtained.release();
waitUntiAccessTokenIsObtained.release();
}
@Override
public void onFailure(Call<AccessToken> call, Throwable t) {
Log.e("MainActivity", "could not retrieve access token", t);
}
});
}
}
public类MainActivity扩展了AppCompatActivity{
私有BottomNavigationView BottomNavigationView;
私有的最后一个字符串是\u FIRST\u USE\u FLAG=“IS\u FIRST\u USE\u FLAG”;
信号量WaitUntiAccessTokenIsTained=新信号量(0);
私有静态布尔值isFirstUseFlagValue;
共享引用优先权;
客户凭证商店凭证商店;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
prefs=this.getSharedReferences(“com.myapp”,Context.MODE\u PRIVATE);
handleFlags();
if(this.isFirstUseFlagValue){
registerClient();
getAccessToken();
试一试{
waitUntiAccessTokenIsTained.acquire();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
setContentView(右布局主屏幕);
bottomNavigationView=(bottomNavigationView)findViewById(R.id.navigation);
底部导航视图
.setOnNavigationItemSelectedListener
(新的BottomNavigationView.OnNavigationItemSelectedListener(){
@凌驾
公共布尔值onNavigationItemSelected(@NonNull MenuItem item){
片段selectedFragment=null;
开关(item.getItemId()){
案例R.id.action_第1项:
selectedFragment=HomeFragment.newInstance();
打破
案例R.id.action_项目2:
selectedFragment=CathegoriesListFragment.newInstance();
打破
案例R.id.action_第3项:
selectedFragment=TestFragment.newInstance();
打破
案例R.id.action_第4项:
selectedFragment=ItemThreeFragment.newInstance();
打破
}
FragmentTransaction=getSupportFragmentManager().beginTransaction();
事务.替换(R.id.frame\U布局,selectedFragment);
commit();
返回true;
}
});
//手动显示第一个片段-仅一次
FragmentTransaction=getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_布局,HomeFragment.newInstance());
commit();
//用于以编程方式选择项目
//bottomNavigationView.getMenu().getItem(1).setChecked(true);
}
私有无效句柄(){
this.isFirstUseFlagValue=prefs.getBoolean(this.IS_FIRST_USE_FLAG,true);
}
私有无效注册表客户端(){
//在服务器上进行TODO客户端注册。
字符串clientNameValue=“clientId”;
字符串clientPasswordValue=“clientSecret”;
credentialsStore=新客户端credentialsStore(getApplicationContext());
保存(clientNameValue、clientPasswordValue);
}
私有void getAccessToken(){
//从服务器获取令牌。
ClientCredentialsStore credentialsStore=新的ClientCredentialsStore(getApplicationContext());
ClientCredentials=credentialsStore.getCredentials();
Call Call=ClientAPI.oAuth2ClientCredentialsGrant(凭证).tokenClient(
ClientAccessTokenRequest.from());
call.enqueue(新回调(){
@凌驾
公共void onResponse(呼叫,改装2.响应){
AccessToken AccessToken=response.body();
TokenStore=新的TokenStore(getApplicationContext());
store.save(accessToken);
WaitUntiAccessTokenIsTained.release();
WaitUntiAccessTokenIsTained.release();
}
@凌驾
失败时公共无效(调用调用,可丢弃的t){
Log.e(“MainActivity”,“无法检索访问令牌”,t);
}
});
}
}
永远不要在主线程上等待信号量。主线程不得因任何原因延迟。这样做会使你的应用程序看起来没有反应(绘图命令将不会被处理),并最终触发一个看门狗定时器,这将杀死你的应用程序。在您的数据可用之前,请设置加载屏幕。同步请求如何?谢谢。不,同步请求也会有同样的问题。答案是你不要等待。从接收令牌开始,您将需要访问令牌的所有逻辑放在回调中。如有必要,您最初会显示一个加载屏幕,并在令牌到达时更改UI。