Java Android、异步、回调和UI
我有一个棘手的问题,就是如何把这些东西整合成一个整体。 示例:我想获取用户位置并用纬度和经度值更新UI。因为我坚持MVC模式,所以我为此任务创建了一个单独的类,例如LocationWorker,并按照以下指南实现了它: 问题:在这种情况下,onConnected回调位于LocationWorker类中,无法与UI通信。我曾尝试在MainActivity类中实现onConnected回调,还添加了GoogleAppClient.ConnectionCallbacks的实现,但在尝试对空对象引用调用虚拟方法“methodName”时出错。看起来在Worker之前执行的回调实际上在连接到get user location之后完成了所有工作,但是OnConnectedCallback在连接之后,在它有时间获取任何数据之前被触发Java Android、异步、回调和UI,java,android,android-asynctask,callback,Java,Android,Android Asynctask,Callback,我有一个棘手的问题,就是如何把这些东西整合成一个整体。 示例:我想获取用户位置并用纬度和经度值更新UI。因为我坚持MVC模式,所以我为此任务创建了一个单独的类,例如LocationWorker,并按照以下指南实现了它: 问题:在这种情况下,onConnected回调位于LocationWorker类中,无法与UI通信。我曾尝试在MainActivity类中实现onConnected回调,还添加了GoogleAppClient.ConnectionCallbacks的实现,但在尝试对空对象引用调
无论如何,这对我来说是一个巨大的问题,我应该使用什么来拥有异步任务,并且在异步任务完成时能够更新UI而不破坏MVC?有一个get-in-AsyncTask,它将在请求完成时触发,并将返回您在创建异步任务时指定的返回类型
eg : ImageGrabber extends AsyncTask<String, String, Bitmap>
异步类:
//We can attach any object to the async class for result
private class MyAsyncTask extends AsyncTask<Void,MyObject,MyObject >{
@Override
protected MyObject doInBackground(Void... params) {
//Do the work to get your data
//this is done in a background thread
//prepare the result
//MyObject object = new MyObject();
//object.setLong(LONG);
//object.setLang(LANG);
//You can pass the result here
//return object;
return null;
}
@Override
protected void onPostExecute(MyObject object) {
super.onPostExecute(object);
//Update UI
//this is done on the main thread
//access data from the Object result
//object.getLong();
//object.getLang();
}
}
如果您想简化UI和任何任务之间的通信,我建议使用此框架将任务与UI分离: 一个事件总线就是你用最小的学习曲线来完成你想要做的事情所需要的一切。 用户界面将订阅任务发布的事件:
public class LocationEvent {
private float lat, lng;
public LocationEvent(float lat, float lng) { this.lat=lat; this.lng=lng; }
}
MainActivity {
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
public void onEvent(LocationEvent event) {
// update user location
}
}
LocationWorker {
void doSomething() {
eventBus.post(new LocationEvent(lat, lng));
}
}
使用作业队列代替AsyncTask将使您的任务/作业更易于管理,并具有重试和持久性的额外好处。
看看EventBus看起来很有希望 另一种选择是使用意图和广播接收器 例如: 在MainActivity.java中:
@Override
public void onResume() {
super.onResume();
IntentFilter iFilter= new IntentFilter("updatelocation");
iFilter.addAction("someOtherAction"); //if you want to add other actions to filter
this.registerReceiver(br, iFilter);
}
@Override
public void onPause() {
this.unregisterReceiver(br);
super.onPause();
}
private BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("UpdateLocation")){
//set these to member variables for later retrieval
double lat = intent.getExtras().getDouble("lat");
double lon = intent.getExtras().getDouble("lon");
this.runOnUiThread(mUpdateLocation);
}
}
};
private final Runnable mUpdateLocation = new Runnable() {
@Override
public void run() {
//TODO: Update your UI here
}
};
然后,在LocationWorker类中,当位置发生更改时发送意图。确保在LocationWorker类中有对应用程序上下文的引用
见此帖:
使用新的Asynctaskname.execute.get;它将首先完成异步任务,然后执行下一个任务。这是个好主意,尽管如果我使用所描述的方法获取一个人的位置,我已经有了一个OnConnected回调方法。所以,如果我理解正确,我所需要的就是从OnConnected回调调用Async任务?在本例中,异步任务准备所有数据并将其返回到UI线程。如果是,只需在MainActivity中实现一个OnConnected回调?回调是一个好方法是的,我同意。虽然您知道有很多选项:等待,如果数据随回调一起出现,则无需在异步中进行准备。仅对可能阻塞UIT的内容使用异步。这正是问题所在,在建立到位置服务的连接时会触发回调,但此时没有数据。我认为此时应该开始接收数据,但是如何通知UI我已经完成了数据提取?这可以被认为是进行回调的一种常见且正确的做法吗?不。您的做法正好是使用异步任务…建立连接必须在单独的线程上完成
public class LocationEvent {
private float lat, lng;
public LocationEvent(float lat, float lng) { this.lat=lat; this.lng=lng; }
}
MainActivity {
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
public void onEvent(LocationEvent event) {
// update user location
}
}
LocationWorker {
void doSomething() {
eventBus.post(new LocationEvent(lat, lng));
}
}
@Override
public void onResume() {
super.onResume();
IntentFilter iFilter= new IntentFilter("updatelocation");
iFilter.addAction("someOtherAction"); //if you want to add other actions to filter
this.registerReceiver(br, iFilter);
}
@Override
public void onPause() {
this.unregisterReceiver(br);
super.onPause();
}
private BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("UpdateLocation")){
//set these to member variables for later retrieval
double lat = intent.getExtras().getDouble("lat");
double lon = intent.getExtras().getDouble("lon");
this.runOnUiThread(mUpdateLocation);
}
}
};
private final Runnable mUpdateLocation = new Runnable() {
@Override
public void run() {
//TODO: Update your UI here
}
};
//Make sure you have a reference to the application context
Intent updateLocation= new Intent(context, MainActivity.class);
updateLocation.setAction("UpdateLocation");
updateLocation.putExtra("lon", xLocation.getLongitude());
updateLocation.putExtra("lat", xLocation.getLatitude());
context.sendBroadcast(i);