我正在尝试为Android应用实现基本登录屏幕。流程如下:
1)用户输入登录信息并点击提交
2)创建并执行扩展LoginRequest
的{{1}}
3)AsyncTask
将激活一些http调用以验证用户凭证
4)应调用doInBackground
来设置onPostExecute
5)Ui线程看到登录结果并继续相应。
我一直在简化代码以解决根本问题,但到目前为止还没有任何运气。以下是仍然重现问题的简化代码。
在我的活动中:
loginResults
这是通过点击监听器上的提交按钮调用的。
在LoginHelper中:
private void tryLogin(String email, String password)
{
this.showProgress(true);
LoginHelper loginHelper = new LoginHelper();
LoginResult result = loginHelper.tryLogin(email, password);
this.showProgress(false);
}
这将执行AsyncTask并等待结果继续。
LoginRequest:
TestClass test = new TestClass();
public LoginResult tryLogin(String mobileNumber, String password, int deviceId)
{
String loginUrl = "...";
new LoginRequest(test).execute(loginUrl);
while (test.result == null)
{
try {
Thread.sleep(1000);
}
catch (Exception e)
{
//...
}
}
return test.result;
}
我在调试器中使用public class LoginRequest extends AsyncTask<String, Void, LoginResult>
TestClass test;
public LoginRequest(TestClass test)
{
this.test = test;
}
@Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1,"test");
return ret;
}
@Override
protected void onPostExecute(LoginResult result) {
this.test.result = result;
}
}
和doInBackground
内的断点运行此操作。 onPostExecute
正确执行并返回doInBackground
值,但LoginResult
断点永远不会被命中,我的代码将在onPostExecute
中的while循环中等待。
答案 0 :(得分:0)
它的AsyncTask因此它同时调用LoginRequest和while(test.result)。你陷入了while循环,因为test.result还没有返回。 test.result在onPostExecute()中完成,所以如果你在该函数中移动while循环它将起作用并且onPostExecute()将被调用。解决此问题的一种方法是实现回调接口。将while循环放在覆盖的回调方法中。 请参考我的回答:how to send ArrayList(Bitmap) from asyncTask to Fragment and use it in Arrayadapter
答案 1 :(得分:0)
试一下
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
{
TestClass test;
LoginResult ret = null;
public LoginRequest(TestClass test)
{
this.test = test;
}
@Override
protected Boolean doInBackground(String... params) {
ret = new LoginResult(1,"test");
return true;
}
@Override
protected void onPostExecute(Boolean success) {
if(success)
this.test.result = result;
}
}
答案 2 :(得分:0)
临时解决方案:您可以在this.test.result = result;
方法中添加doInbackground()
。
@Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1, "test");
this.test.result = result;
return ret;
}
请发布完整代码以获得正确的解决方案。
答案 3 :(得分:0)
您基本上是在检查LoginRequest的变量“result”的整个时间。但事实并非如此,AsyncTask如何运作。
来自Docs:
AsyncTask允许您对用户执行异步工作 接口。它在工作线程中执行阻塞操作 然后在UI线程上发布结果,无需您 自己处理线程和/或处理程序。
您可以使用 doInBackground()方法进行工作,然后将结果发布到 onPostExecute()。
onPostExecute在UI线程上运行,允许您更改元素,显示结果或您想要执行的任何操作。您的问题是,您一直在使用tryLogin()
中的检查方法阻止UI线程那么如何解决呢?
删除检查方法:
public void tryLogin(String mobileNumber, String password, int deviceId)
{
// Starts AsynTasks, handle results there
String loginUrl = "...";
new LoginRequest().execute(loginUrl);
}
在AsyncTask中:
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
// Removed Constructor, if you need to pass some other variables, add it again
@Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
@Override
protected void onPostExecute(LoginResult result) {
// Now the result arrived!
// TODO: Use the result
}
}
更多想法:
的AsyncTask:
公共类LoginRequest扩展了AsyncTask
private Activity activity;
// Constructor
public LoginRequest(Activity activity) {
this.activity = activity;
}
@Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
@Override
protected void onPostExecute(LoginResult result) {
ActivityLogin acLogin = (ActivityLogin) activity;
if(result.equals("ok")) {
Button loginButton = (Button) acLogin.findViewById(R.id.login-button);
loginButton.setBackgroundColor(Color.GREEN);
//Finish LoginActivity
acLogin.finish();
}
else {
//TODO: Fail Handling
}
}
}
开始就像这样:
new LoginRequest(loginActivity).execute(loginUrl);
我没有测试过代码。