首先看运行效果:实现的是上,下拉刷新的效果。
本文主要介绍使用android开源项目PullToRefresh-master,实现上下拉刷新。
首先下载library,将library添加到项目依赖中,项目的主要目录结构如下:
主要的知识都在代码中注释,首先activity.xml中是这样配置:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<com.handmark.pulltorefresh.library.PullToRefreshListView
android:id="@+id/pull_refresh_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:divider="#19000000"
android:dividerHeight="4dp"
android:fadingEdge="none"
android:fastScrollEnabled="false"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:smoothScrollbar="true" />
</LinearLayout>
还有item.xml的文件,显示的是每个listview中显示的内容
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textview"
android:layout_width="fill_parent"
android:layout_height="30dp"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:text="123" />
</LinearLayout>
MainActivity中的代码如下:
package app.myapplication;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.format.DateUtils;
import android.widget.ListView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
import java.util.ArrayList;
public class MainActivity extends ActionBarActivity {
//设置集合
private ArrayList list;
//设置适配器
private MyAdapter adapter;
PullToRefreshListView pull_refresh_list;
//设置一个标记,判断是下拉还是上拉;
private Boolean isPullDown = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new ArrayList();
pull_refresh_list = (PullToRefreshListView) findViewById(R.id.pull_refresh_list);
//初始化集合
initData();
adapter = new MyAdapter(MainActivity.this, list);
pull_refresh_list.setAdapter(adapter);
//设置拉伸的模式,both代表上,下都能拉伸,默认的是只能下拉刷新;
pull_refresh_list.setMode(PullToRefreshBase.Mode.BOTH);
pull_refresh_list.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() {
//下拉的时候执行
@Override
public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {
//label主要 设置下拉刷新时候显示的内容;
String label = DateUtils.formatDateTime(getApplicationContext(),
System.currentTimeMillis(),
DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_ABBREV_ALL);
//把显示的内容设置到控件中
refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);
isPullDown = true;
//异步任务,主要作耗时操作,实际开发中是应该联网,从服务器或者数据库中获取数据;
new LoadData().execute();
}
//上拉的时候执行
@Override
public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
isPullDown = false;
//在下拉的时候同样执行操作,由isPullDown标识是下拉,或者下拉
new LoadData().execute();
}
});
}
public class LoadData extends AsyncTask<Integer, Integer, String> {
//在doInBackground中作主要的耗时操作,比如连网,查询。在这只让休眠1秒中;
@Override
protected String doInBackground(Integer... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
//在doInBackground方法执行后执行此方法,主要负责更新UI界面和数据;
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (isPullDown) {
//在下拉时给集合中添加元素;
list.add(0, "我是下拉出来的数据");
} else {
//在上拉时给集合中添加元素;
list.add(list.size(), "我是上拉出来的数据");
}
//能过nofifyDataSetChanged()方法,不用刷新Activity,只刷新listview;
adapter.notifyDataSetChanged();
//下拉刷新结束后,把拉出来的布局隐藏;
pull_refresh_list.onRefreshComplete();
}
}
private void initData() {
for (int i = 0; i < 10; i++) {
list.add(" 我是item " + i);
}
}
}
最后适配器中的代码也比较简单:
package app.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
/**
* Created by Administrator on 2015/9/8.
*/
public class MyAdapter extends BaseAdapter {
ArrayList arraylist;
Context context;
public MyAdapter(Context context, ArrayList arraylist) {
this.context = context;
this.arraylist = arraylist;
}
@Override
public int getCount() {
return arraylist.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if (convertView == null) {
vh = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
vh.textview = (TextView) convertView.findViewById(R.id.textview);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
vh.textview.setText(arraylist.get(position) + "");
return convertView;
}
static class ViewHolder {
TextView textview;
}
}
在PullToRrefresh中如果要设置进入到页面(比如聊天页面,显示最后一条消息)要设置这样的属性
pullToRefresh.getRefreshableView().setSelection(
arrayList.size() - 1);
2、AsyncTask总结
1、AsyncTask的内部原理:
在以前代码中
private static final int CORE_POOL_SIZE =5;//5个核心工作线程
private static final int MAXIMUM_POOL_SIZE = 128;//最多128个排队线程
private static final int KEEP_ALIVE = 1;//空闲线程的超时时间为1秒
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);//等待队列
private static final ThreadPoolExecutorsExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue,sThreadFactory);//线程池是静态变量,所有的异步任务都会放到这个线程池的工作线程内执行。
但是从6.0sdk中面
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//为cup的核心+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);//依然是128个最多排队线程
2、AsyncTask中的实现原理
(1)、AsyncTask的底层是线程池+UI线程,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均运行在主线程中UI线程中执行,这样就不用Handler发消息处理了;
(2)、AsyncTask实际工作的也就是5个线程,也就是说,一个APP如果运用AsyncTask技术来执行线程,那么同一时间最多只能有5个线程同时运行,其他线程将被所以AsyncTask不要用于多线程取网络数据,因为很可能这样会产生阻塞,从而降低效率。
(3)、AsyncTask用的是线程池机制,容量是128等线程,最多同时运行5个core线程,剩下的排队。线程池中如果已经有128个线程,缓冲队列已满,如果此时向线程提交任务,将会抛出RejectedExecutionException
3、AsyncTask中的常见问题
在Activity中创建的AsyncTask并不会随着Activity的销毁而结束任务,因此在Activity销毁前的时候我们必须取消任务请求。
4、AsyncTask的重要参数和方法
三个参数:
1、Params 在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
2、Progress后台任何执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
3、Result 当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
四个方法:
1、onPreExecute()
这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
2、doInBackground(Params…)
做耗时操作,比如从服务器获取数据。
3、onProgressUpdate(Progress…)
比如更新进度条,显示进度值。
4、onPostExecute(Result)
获取数对话据,关闭框。
示例代码
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}