我有一个Recycler View, 用于显示从服务器下载的信息。为了使其具有响应性,我使用了async/await操作和Tasks进行编写。问题是当它等待信息下载完成时,UI仍在运行,这要么导致程序崩溃因为尚未下载任何信息,要么没有显示所有信息。
如果
而对于
代码:
如果
GetDevicesInfo()
是异步的,应用程序将崩溃,因为还没有信息可以显示。但奇怪的是,如果我将代码放入调用该方法的位置(然后注释掉该调用),它就可以正常工作。而对于
DisplaySensorStates()
则不同,如果该方法不是异步的话,情况也是如此:
...当它是异步的时候:
显然,当它下载温度信息时,视图已经显示了现有的项目,这只是第一个。代码:
namespace *********.Fragments {
public class Dashboard : GridLayoutBase {
JsonFetcher jsonFetcher;
private ISharedPreferences pref;
private SessionManager session;
private string cookie;
private DeviceModel deviceModel;
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private List<ItemData> itemData;
public static Activity activity;
private SwipeRefreshLayout swipeRefreshLayout;
private const string URL_DASHBOARD = "http://10.1.1.20/appapi/getdashboard";
private const string URL_DATA = "http://10.1.1.20/appapi/getdata";
public async override void OnStart() {
base.OnStart();
activity = Activity;
session = new SessionManager();
pref = Activity.GetSharedPreferences("UserSession", FileCreationMode.Private);
cookie = pref.GetString("PHPSESSID", string.Empty);
GetDevicesInfo();
DisplaySensorStates();
DisplayLastPhoto();
adapter = new ViewAdapter(itemData);
new System.Threading.Thread(new System.Threading.ThreadStart(() => {
Activity.RunOnUiThread(() => {
recyclerView.SetAdapter(adapter);
});
})).Start();
}
public async void GetDevicesInfo() {
var jsonFetcher = new JsonFetcher();
JsonValue jsonDashboard = await jsonFetcher.FetchDataWithCookieAsync(URL_DASHBOARD, cookie);
deviceModel = new DeviceModel();
deviceModel = JsonConvert.DeserializeObject<DeviceModel>(jsonDashboard);
}
// Shows sensor states
public async void DisplaySensorStates() {
itemData = new List<ItemData>();
foreach (var sensor in this.deviceModel.Sensors) {
string lastValue = String.Empty;
if (sensor.Type == "2") { // Temperature
var jsonFetcher = new JsonFetcher();
JsonValue jsonData = await jsonFetcher.FetchSensorDataAsync(URL_DATA, sensor.Id, "ASC", cookie);
var deviceModel = new DeviceModel();
deviceModel = JsonConvert.DeserializeObject<DeviceModel>(jsonData);
lastValue = deviceModel.SensorData.Last().Value;
}
itemData.Add(new ItemData() {
id = sensor.Id,
value = lastValue,
type = sensor.Type,
image = Resource.Drawable.smoke_red,
title = sensor.Name.First().ToString().ToUpper() + sensor.Name.Substring(1).ToLower(),
});
}
}
// Shows the last camera photo
public async void DisplayLastPhoto() {
// if (deviceModel.Error == "true" && deviceModel.ErrorType == "noPhoto") {
// //TODO: Show a "No photo" picture
// } else {
// string url = deviceModel.LastPhotoLink;
// Bitmap imageBitmap = await new ImageDownloader().GetImageBitmapFromUrlAsync(url, Activity, lastPhoto.Width, lastPhoto.Height);
// lastPhoto.SetImageBitmap(imageBitmap);
// imageBitmap.Dispose();
// }
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.Inflate(Resource.Layout.Dashboard, container, false);
SwipeRefreshLayout swipeRefreshLayout = view.FindViewById<SwipeRefreshLayout>(Resource.Id.swipe_container);
// swipeRefreshLayout.SetColorSchemeResources(Color.LightBlue, Color.LightGreen, Color.Orange, Color.Red);
// On refresh button press/swipe, refreshes the recycler view
swipeRefreshLayout.Refresh += async (sender, e) => {
this.GetDevicesInfo();
new System.Threading.Thread(new System.Threading.ThreadStart(() => {
Activity.RunOnUiThread(() => {
this.DisplaySensorStates();
adapter = new ViewAdapter(itemData);
// itemData[0].title = "Dooooooors";
// Console.WriteLine(itemData[0].title);
recyclerView.SetAdapter(adapter);
// Console.WriteLine ("yes");
adapter.NotifyDataSetChanged();
// recyclerView.Invalidate();
swipeRefreshLayout.Refreshing = false;
});
})).Start();
};
recyclerView = view.FindViewById<RecyclerView>(Resource.Id.dashboard_recycler_view);
layoutManager = new GridLayoutManager(Activity, 3);
recyclerView.HasFixedSize = true;
recyclerView.SetLayoutManager(layoutManager);
recyclerView.SetItemAnimator(new DefaultItemAnimator());
recyclerView.AddItemDecoration(new SpaceItemDecoration(8));
return view;
}
public class ViewAdapter : RecyclerView.Adapter {
private List<ItemData> itemData;
public string sensorId;
public string sensorType;
private ImageView imageId;
private TextView sensorValue;
private TextView sensorStatus;
public ViewAdapter(List<ItemData> itemData) {
this.itemData = itemData;
}
public class ItemView : RecyclerView.ViewHolder {
public View mainView { get; set; }
public string id { get; set; }
public string type { get; set; }
public ImageView image { get; set; }
public TextView value { get; set; }
public TextView status { get; set; }
public ItemView(View view) : base(view) {
mainView = view;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
View itemLayoutView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.DashboardItems, null);
CardView cardView = itemLayoutView.FindViewById<CardView>(Resource.Id.dashboard_card_view);
imageId = itemLayoutView.FindViewById<ImageView>(Resource.Id.sensor_image);
sensorValue = itemLayoutView.FindViewById<TextView>(Resource.Id.sensor_value);
sensorStatus = itemLayoutView.FindViewById<TextView>(Resource.Id.sensor_status);
var viewHolder = new ItemView(itemLayoutView) {
id = sensorId,
type = sensorType,
image = imageId,
value = sensorValue,
status = sensorStatus
};
return viewHolder;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
ItemView itemHolder = viewHolder as ItemView;
if (itemData[position].type == "2") { // Temperature
// itemHolder.image.Visibility = ViewStates.Invisible;
itemHolder.value.Text = itemData[position].value;
}
itemHolder.image.SetImageResource(itemData[position].image);
itemHolder.status.Text = itemData[position].title;
EventHandler clickUpdateViewEvent = ((sender, e) => {
var bundle = new Bundle();
var dualColumnList = new DualColumnList();
bundle.PutString("id", itemData[position].id);
dualColumnList.Arguments = bundle;
((FragmentActivity)activity).ShowFragment(dualColumnList, itemData[position].title, itemData[position].type);
});
itemHolder.image.Click += clickUpdateViewEvent;
itemHolder.value.Click += clickUpdateViewEvent;
itemHolder.status.Click += clickUpdateViewEvent;
}
public override int ItemCount {
get { return itemData.Count; }
}
}
public class ItemData {
public string id { get; set; }
public string type { get; set; }
public int image { get; set; }
public string value { get; set; }
public string title { get; set; }
}
}
}
我该如何修复这个问题?