我正在开发一个带有由Bitmaps填充的自定义ListView的应用。位图很好地加载但唯一的问题是每次滚动ListView时,进入视图的图像都会被重新加载,即使它们之前已经加载过。这浪费时间并且效率很低。我想要一种获取图像的方法,当ListView将位图滚入和移出视图时,不必重新加载它们。这是我的代码(只是抛出所有内容......你正在寻找MainAdapter和AsyncCaller):
public class Post extends SherlockActivity implements
PullToRefreshAttacher.OnRefreshListener, OnItemClickListener {
private PullToRefreshAttacher mPullToRefreshAttacher;
private ListView listview;
private DisplayMetrics metrics;
String[] index = { "023", "143", "564", "982", "023", "143", "564", "982",
"023", "143", "564", "982" };
String[] summary = { "One", "Two", "Three", "Four", "Five",
"Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve" };
String[] images = {
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c",
"https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTpgdQYIzGWZiDsCtWIMzuZVaZABIwC-3Ym9gvGMcV5OVUdAb-c" };
ActionMode mMode;
Animation animation;
Intent i;
URL img_url;
Bitmap bmp = null;
Holder holder;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (Session.getActiveSession() == null) {
i = new Intent(getApplicationContext(), StartBase.class);
startActivity(i);
} else {
retrieveData();
setUpFacebook();
sessionCheck();
}
}
private void setUpFacebook() {
// TODO Auto-generated method stub
String APP_ID = getString(R.string.app_id);
FacebookRef.fb = new Facebook(APP_ID);
FacebookRef.asyncrunner = new AsyncFacebookRunner(FacebookRef.fb);
}
private void retrieveData() {
// TODO Auto-generated method stub
// Parse work: Get the data and create the list. The data has to have
// the Bitmaps
}
private void sessionCheck() {
// TODO Auto-generated method stub
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
// Get the user's data
listview = new ListView(this);
listview.setFadingEdgeLength(0);
ArrayList<String> strings = new ArrayList<String>();
ArrayList<String> urls = new ArrayList<String>();
int pos = 0;
// As long as it is less than the number of items in the string
// array
for (int i = 0; i < summary.length; i++) {
strings.add(summary[pos]);
urls.add(images[pos]);
pos++;
}
MainAdapter mAdapter = new MainAdapter(this, strings, urls, metrics);
listview.setAdapter(mAdapter);
listview.setOnItemClickListener(this);
setContentView(listview);
pullToRefresh();
} else {
Toast.makeText(getApplicationContext(), "Please log in first",
Toast.LENGTH_LONG).show();
i = new Intent(getApplicationContext(), StartBase.class);
startActivity(i);
}
}
private void pullToRefresh() {
// TODO Auto-generated method stub
PullToRefreshAttacher.Options ptrOptions = new PullToRefreshAttacher.Options();
ptrOptions.refreshScrollDistance = 0.6f;
ptrOptions.headerLayout = R.layout.customised_header;
ptrOptions.headerTransformer = new CustomisedHeaderTransformer();
mPullToRefreshAttacher = PullToRefreshAttacher.get(this, ptrOptions);
PullToRefreshAttacher.ViewDelegate handler = new AbsListViewDelegate();
mPullToRefreshAttacher.addRefreshableView(listview, handler, this);
}
@Override
public void onRefreshStarted(View view) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Works",
Toast.LENGTH_LONG).show();
new AsyncCaller().execute();
}
}).start();
// Notify PullToRefreshAttacher that the refresh has finished
mPullToRefreshAttacher.setRefreshComplete();
}
static class CustomisedHeaderTransformer extends
PullToRefreshAttacher.HeaderTransformer {
private View mHeaderView;
private TextView mMainTextView;
private TextView mProgressTextView;
@Override
public void onViewCreated(Activity activity, View headerView) {
mHeaderView = headerView;
mMainTextView = (TextView) headerView.findViewById(R.id.ptr_text);
mProgressTextView = (TextView) headerView
.findViewById(R.id.ptr_text_secondary);
}
@Override
public void onReset() {
mMainTextView.setVisibility(View.VISIBLE);
mMainTextView.setText(R.string.pull_to_refresh_pull_label);
mProgressTextView.setVisibility(View.GONE);
mProgressTextView.setText("");
}
@Override
public void onPulled(float percentagePulled) {
mProgressTextView.setVisibility(View.VISIBLE);
mProgressTextView
.setText(Math.round(100f * percentagePulled) + "%");
}
@Override
public void onRefreshStarted() {
mMainTextView.setText(R.string.pull_to_refresh_refreshing_label);
mProgressTextView.setVisibility(View.GONE);
}
@Override
public void onReleaseToRefresh() {
mMainTextView.setText(R.string.pull_to_refresh_release_label);
}
@Override
public void onRefreshMinimized() {
// In this header transformer, we will ignore this call
}
@Override
public boolean showHeaderView() {
final boolean changeVis = mHeaderView.getVisibility() != View.VISIBLE;
if (changeVis) {
mHeaderView.setVisibility(View.VISIBLE);
}
return changeVis;
}
@Override
public boolean hideHeaderView() {
final boolean changeVis = mHeaderView.getVisibility() != View.GONE;
if (changeVis) {
mHeaderView.setVisibility(View.GONE);
}
return changeVis;
}
}
@Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
com.actionbarsherlock.view.MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.main, menu);
com.actionbarsherlock.view.SubMenu subMenu1 = menu
.addSubMenu("Categories");
subMenu1.add(0, 1, Menu.NONE, "Entertainment");
subMenu1.add(0, 2, Menu.NONE, "Fashion");
subMenu1.add(0, 3, Menu.NONE, "Business");
subMenu1.add(0, 4, Menu.NONE, "Books");
subMenu1.add(0, 5, Menu.NONE, "Kids");
subMenu1.add(0, 6, Menu.NONE, "Home");
com.actionbarsherlock.view.MenuItem subMenu1Item = subMenu1.getItem();
subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS
| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(
com.actionbarsherlock.view.MenuItem item) {
switch (item.getItemId()) {
case 1:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case 2:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case 3:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case 4:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case 5:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case 6:
Toast.makeText(getApplicationContext(), item.getTitle(),
Toast.LENGTH_LONG).show();
break;
case R.id.action_account:
i = new Intent(getApplicationContext(), Account.class);
startActivity(i);
break;
case R.id.action_logout:
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("Logout?");
alertDialog.setMessage("Are you sure you want to logout?");
alertDialog.setIcon(android.R.drawable.ic_lock_power_off);
alertDialog.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(), "Logout",
Toast.LENGTH_LONG).show();
Session.getActiveSession()
.closeAndClearTokenInformation();
i = new Intent(getApplicationContext(),
StartBase.class);
startActivity(i);
}
});
alertDialog.setNegativeButton("No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
break;
}
return super.onOptionsItemSelected(item);
}
private class Holder {
public TextView textview;
public ImageView imageView;
}
public class MainAdapter extends ArrayAdapter<String> {
private Context context;
private LayoutInflater mInflater;
private ArrayList<String> strings;
private ArrayList<String> urls;
private DisplayMetrics metrics_;
public MainAdapter(Context context, ArrayList<String> strings,
ArrayList<String> urls, DisplayMetrics metrics) {
super(context, 0, strings);
this.context = context;
this.mInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.strings = strings;
this.urls = urls;
this.metrics_ = metrics;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
final String str = this.strings.get(position);
final String url = this.urls.get(position);
if (convertView == null) {
convertView = mInflater
.inflate(R.layout.custom_list_item, null);
holder = new Holder();
holder.textview = (TextView) convertView
.findViewById(R.id.text);
holder.textview.setTextColor(0xFFFFFFFF);
holder.imageView = (ImageView) convertView
.findViewById(R.id.pic);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
try {
img_url = new URL(url);
holder.imageView.setBackgroundResource(R.drawable.logo);
new AsyncCaller().execute();
holder.textview.setText(str);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
animation = AnimationUtils.loadAnimation(context,
R.anim.push_left_in);
animation.setDuration(200);
convertView.startAnimation(animation);
animation = null;
return convertView;
}
}
private class AsyncCaller extends AsyncTask<Void, Void, Void> {
ProgressDialog pdLoading = new ProgressDialog(Post.this);
@Override
protected void onPreExecute() {
super.onPreExecute();
pdLoading.setMessage("Loading...");
pdLoading.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
bmp = BitmapFactory.decodeStream(img_url.openConnection()
.getInputStream());
bmp = RoundBitmap.roundCorner(bmp, 20);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
holder.imageView.setImageBitmap(bmp);
pdLoading.dismiss();
}
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "List item selected",
Toast.LENGTH_LONG).show();
i = new Intent(getApplicationContext(), AdDetails.class);
Bundle b = new Bundle();
b.putString("index", index[arg2]);
b.putString("summary", summary[arg2]);
b.putString("url", images[arg2]);
i.putExtras(b);
startActivity(i);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if (keyCode == KeyEvent.KEYCODE_BACK) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("Leave?");
alertDialog.setMessage("Are you sure you want to leave?");
alertDialog.setIcon(android.R.drawable.ic_lock_power_off);
alertDialog.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
android.os.Process.killProcess(android.os.Process
.myPid());
}
});
alertDialog.setNegativeButton("No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
return super.onKeyDown(keyCode, event);
}
}
答案 0 :(得分:1)
简单方法 - 使用毕加索(http://square.github.io/picasso/)
答案 1 :(得分:1)
Android Developer文档中有一个很好的Training guide。
答案 2 :(得分:0)
我可能错了,但我认为问题在于滚动应用程序时认为它正在进行某种配置更改。根据我最近编写线程进程的经验,在旋转屏幕时,我不希望重新启动下载或重新加载某些对象。在那里硬编码的文件仍然使用他们的ID,但其他文件被重新加载。
解决方案是使用两种方法,一种方法可以识别何时有配置更改,然后获取所需的对象并将它们传递给弱引用,然后另一种方法询问我们是否刚刚来自配置更改并且如果这样从那些弱引用加载那些对象。