java - 信号量阻塞线程但不会释放它

标签 java android concurrency semaphore

基本上,这里的想法是等到服务器发送访问 token ,否则资源将被旧的 token 加载并且应用程序崩溃。但是在 getAccessToken() 异步请求中获取 token 并使用 waitUntiAccessTokenIsObtained.release() 释放许可后,主线程保持阻塞状态。 waitUntiAccessTokenIsObtained.acquire() 被放置在 MainActivityonCreate 方法中。我错过了什么?

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);
                }
            });
        }
}

最佳答案

永远不要在主线程上等待信号量。主线程不得因任何原因而延迟。这样做将使您的应用程序显得无响应(绘制命令将不会被处理)并最终触发看门狗计时器,从而杀死您的应用程序。改为设置加载屏幕,直到您的数据可用。

关于java - 信号量阻塞线程但不会释放它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49467823/

相关文章:

java - 是否可以将 AspectJ 与 MBean 一起使用?

java - notification.setOngoing(true) 在 Android 8.1 中不起作用

android - 您无权为您的应用使用内部应用共享

java - 使用Thread.currentThread()。isInterrupted()与Thread.sleep()

ruby-on-rails - Rails 4 并发数据库索引

java - 我如何测量有多少线程正在执行一段代码?

java - 如何修复 spring boot 中损坏的 favicon.ico (而子文件夹中的 jpg-s 则没有)?

java - 我想将 java 中的数组中的值存储在我自己类型的 arrayList 中。我该怎么做

java - String[] s = str.split (","的 CPU 使用率

java - 打开下载的 SQLite 数据库