首先,请帮助......我已经完成了几乎所有事情,现在我在这里!
第一个困惑是:为什么Async类工作得太慢,我使用click事件从api获取一些数据,同时使用SYSO查看Android监视器中填充数组的输出,它差不多花了4.5秒每次用20个元素填充arraylist。一定有一些我现在不知道的错误......活动代码是:
Toolbar toolbar;
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_news);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Get Request
String url = "MY URL HERE";
new JSONAsync(getApplicationContext()).execute(url);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(MainNews.this, JSONAsync.dataArray);
recyclerViewAdapter.notifyDataSetChanged();
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(recyclerViewAdapter);
recyclerViewAdapter.notifyDataSetChanged();
}
Async类编写为:
Context context;
public static List<Data> dataArray = new ArrayList<>();
public JSONAsync(Context context) {
this.context = context;
dataArray.clear();
}
@Override
protected Boolean doInBackground(String... params) {
try {
return downloadUrl(params[0]);
} catch (IOException e) {
return false;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public boolean downloadUrl(String myurl) throws IOException, JSONException {
InputStream is = null;
int response;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
response = conn.getResponseCode();
is = conn.getInputStream();
if (response == 200) {
String responseBody = convertToString(conn.getInputStream());
JSONArray jArray = new JSONArray(responseBody);
for (int i = 0; i < jArray.length(); i++) {
JSONObject jobj = jArray.getJSONObject(i);
System.out.println("Output is: ....."+jobj);
Data data = new Data();
data.setId(jobj.getInt("id"));
data.setHeading(jobj.getString("heading"));
data.setBrief(jobj.getString("brief"));
data.setDate(jobj.getString("date"));
String imageURL = "http://paktribune.com/images/news/";
imageURL = imageURL.concat(jobj.getString("limage"));
data.setImage(getBitmapFromURL(imageURL));
dataArray.add(data);
}
return true;
} else return false;
} finally {
if (is != null) {
is.close();
}
}
}
public Bitmap getBitmapFromURL(String imageURL) {
Bitmap myBitmap = null;
try {
int responseCode;
URL url = new URL(imageURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
responseCode = connection.getResponseCode();
if (responseCode==200)
{
InputStream input = connection.getInputStream();
myBitmap = BitmapFactory.decodeStream(input);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
return myBitmap;
}
public String convertToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
} catch (IOException e) {
} finally {
try {
is.close();
} catch (IOException e) {
}
}
return sb.toString();
}
@Override
protected void onPostExecute(Boolean result) {
if (result == false) {
Toast.makeText(context, "Unable to fetch data from server", Toast.LENGTH_SHORT).show();
}
}
适配器是:
private LayoutInflater inflater;
Context context;
List<Data> dataArray;
private int lastPosition = -1;
public RecyclerViewAdapter(Context context, List<Data> dataArray) {
this.dataArray = dataArray;
this.context = context;
inflater = LayoutInflater.from(context);
}
@Override
public RecyclerViewAdapter.CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.cardview, parent, false);
CustomViewHolder holder = new CustomViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
Data current = dataArray.get(position);
holder.textView1.setText(current.heading);
holder.textView2.setText(current.date);
holder.textView3.setText(current.brief);
holder.image.setImageBitmap(current.image);
setAnimation(holder.relativeLayout, position);
}
@Override
public int getItemCount() {
return dataArray.size();
}
public static class CustomViewHolder extends admin.myproject.CustomViewHolder {
ImageView image;
RelativeLayout relativeLayout;
TextView textView1, textView2, textView3;
public CustomViewHolder(View itemView) {
super(itemView);
textView1 = (TextView) itemView.findViewById(R.id.heading);
textView2 = (TextView) itemView.findViewById(R.id.date);
textView3 = (TextView) itemView.findViewById(R.id.brief);
image = (ImageView) itemView.findViewById(R.id.imageView);
relativeLayout = (RelativeLayout) itemView.findViewById(R.id.Relative);
}
}
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
任何人都可以告诉我为什么当doInBackground
中的循环完成之前点击某个按钮时,应用程序会移动到下一个活动。
我正在清除dataArray并更新notifyDataSetChanged()
。如果我在notifyDataSetChanged()
或doInBackground()
方法中使用postExecute
,它只会指向Null指针异常,所以这就是我在适配器中使用它的原因,但我认为它是好吧也可以在那里使用它。
请帮助你们!
答案 0 :(得分:1)
您的逻辑存在缺陷,并且实施容易受到许多问题的影响。
1)异步任务,因其名称suggets执行其任务异步。也就是说,行new JSONAsync(getApplicationContext()).execute(url);
立即返回并在活动中继续执行。当您告诉适配器数据已准备就绪时,它很可能没有准备好,异步任务正在尝试同时完成其工作。
2)使用静态成员在多线程环境中进行通信容易出错。相反,在您的活动中实现一个监听器接口,让异步任务在onPostExecute
中调用监听器的方法。然后告诉适配器有关数据的更改。
private List<Data> dataArray = new ArrayList<>();
private IAsyncTaskListener listener;
public JSONAsync(Context context, IAsyncTaskListener listener) {
this.context = context;
this.listener = listener;
}
public interface IAsyncTaskListener {
void onCompleted(List<Data> dataArray);
}
@Override
protected void onPostExecute(Boolean result) {
this.listener.onCompleted(dataArray);
}
您的活动可以实施IAsyncTaskListener
public class YourActivity extends AppCompatActivity implements JSONAsync.IAsyncTaskListener {
@Override
public void onCompleted(List<Data> dataArray) {
recyclerViewAdapter.setData(dataArray);
recyclerViewAdapter.notifyDataSetChanged();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_news);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Get Request
String url = "http://paktribune.com/api/newsList";
new JSONAsync(getApplicationContext(), this).execute(url);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(MainNews.this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(recyclerViewAdapter);
}
}
您将提供一种更改适配器数据的方法。在监听器回调中,您在适配器上设置数据并在其上调用notifyDataSetChanged
,以通知适配器有关更改。
答案 1 :(得分:0)
尝试使用 Picasso 或 Glide 库下载图像。这些库可能提供更快的下载,其缓存处理更好。