Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 信号量阻塞线程,但不会释放它_Java_Android_Concurrency_Semaphore - Fatal编程技术网

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。