加入访问网络和读取,写入sdcard的权限。
[java] view plain copy
接下来,我们来看看MainActivity.java。性能考虑,我们使用convertView和ViewHolder来重用控件。这里涉及到比较关键的一步,我们会在getView的时候给ViewHolder中的ImageView设置tag,其值为要放置在该ImageView上的图片的url地址。这个tag很重要,在异步下载图片完成回调的方法中,我们使用findViewWithTag(String url)来找到ListView中对应的ImagView,然后给该ImageView设置图片即可。其他的就是设置adapter的一般操作了。
[java] view plain copy
-
public class MainActivity extends Activity {
-
ListView mListView;
-
ImageDownloader mDownloader;
-
MyListAdapter myListAdapter;
-
private static final String TAG = “MainActivity”;
-
int m_flag = 0;
-
private static final String[] URLS = {
-
//图片地址就不贴了,自己去这篇帖子中找吧:http://www.cnblogs.com/liongname/articles/2345087.html
-
//其中有几张图片访问不了。
-
};
-
@Override
-
public void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
Util.flag = 0;
-
mListView = (ListView) findViewById(R.id.listview);
-
myListAdapter = new MyListAdapter();
-
mListView.setAdapter(myListAdapter);
-
}
-
private class MyListAdapter extends BaseAdapter {
-
private ViewHolder mHolder;
-
@Override
-
public int getCount() {
-
return URLS.length;
-
}
-
@Override
-
public Object getItem(int position) {
-
return URLS[position];
-
}
-
@Override
-
public long getItemId(int position) {
-
return position;
-
}
-
@Override
-
public View getView(int position, View convertView, ViewGroup parent) {
-
//只有当convertView不存在的时候才去inflate子元素
-
if (convertView == null) {
-
convertView = getLayoutInflater().inflate(R.layout.single_data,
-
null);
-
mHolder = new ViewHolder();
-
mHolder.mImageView = (ImageView) convertView.findViewById(R.id.image_view);
-
mHolder.mTextView = (TextView) convertView.findViewById(R.id.text_view);
-
convertView.setTag(mHolder);
-
}else {
-
mHolder = (ViewHolder) convertView.getTag();
-
}
-
final String url = URLS[position];
-
mHolder.mTextView.setText(url != null ? url.substring(url.lastIndexOf(“/”) + 1) : “”);
-
mHolder.mImageView.setTag(URLS[position]);
-
if (mDownloader == null) {
-
mDownloader = new ImageDownloader();
-
}
-
//这句代码的作用是为了解决convertView被重用的时候,图片预设的问题
-
mHolder.mImageView.setImageResource(R.drawable.ic_launcher);
-
if (mDownloader != null) {
-
//异步下载图片
-
mDownloader.imageDownload(url, mHolder.mImageView, “/yanbin”,MainActivity.this, new OnImageDownload() {
-
@Override
-
public void onDownloadSucc(Bitmap bitmap,
-
String c_url,ImageView mimageView) {
-
ImageView imageView = (ImageView) mListView.findViewWithTag(c_url);
-
if (imageView != null) {
-
imageView.setImageBitmap(bitmap);
-
imageView.setTag(“”);
-
}
-
}
-
});
-
}
-
return convertView;
-
}
-
/**
-
* 使用ViewHolder来优化listview
-
* @author yanbin
-
*
-
*/
-
private class ViewHolder {
-
ImageView mImageView;
-
TextView mTextView;
-
}
-
}
-
}
上面的mDownloader.imageDownload()就是异步下载图片比较核心的方法,该方法在ImageDownloader.java类下。其中的五个参数分别为:要设置在当前ImageView 上的图片的url地址,当前ImageView,文件缓存地址,当前的activity以及图片回调接口。
在ImageDownloader类中,我们首先根据url从软引用中获取图片,如果不存在,从sdcard中读取图片,如果还不存在,则启动一个AsyncTask异步下载图片。注意注意:这里我们做了一个这样的操作:用一个map将当前的url及其对应的MyAsyncTask存放起来了。由于getView会执行至少一次,这一步的操作是为了相同的url创建相同的AsyncTask。在onPostExecute()方法中,将该url对应的信息从map中删除,一定要记得执行这一步。看到很多的异步图片下载的例子中,重复创建AsyncTask都是普遍存在的,这里我们使用上面的思路解决掉了这一问题。更详细的代码自己看ImageDownloader.java类吧,首先给出OnImageDownload.java接口的代码:
[java] view plain copy
-
public interface OnImageDownload {
-
void onDownloadSucc(Bitmap bitmap,String c_url,ImageView imageView);
-
}
ImageDownloader.java的代码(有两百多行,拷贝到eclipse中看会舒服一点):
[java] view plain copy
-
public class ImageDownloader {
-
private static final String TAG = “ImageDownloader”;
-
private HashMap<String, MyAsyncTask> map = new HashMap<String, MyAsyncTask>();
-
private Map<String, SoftReference> imageCaches = new HashMap<String, SoftReference>();
-
/**
-
*
-
* @param url 该mImageView对应的url
-
* @param mImageView
-
* @param path 文件存储路径
-
* @param mActivity
-
* @param download OnImageDownload回调接口,在onPostExecute()中被调用
-
*/
-
public void imageDownload(String url,ImageView mImageView,String path,Activity mActivity,OnImageDownload download){
-
SoftReference currBitmap = imageCaches.get(url);
-
Bitmap softRefBitmap = null;
-
if(currBitmap != null){
-
softRefBitmap = currBitmap.get();
-
}
-
String imageName = “”;
-
if(url != null){
-
imageName = Util.getInstance().getImageName(url);
-
}
-
Bitmap bitmap = getBitmapFromFile(mActivity,imageName,path);
-
//先从软引用中拿数据
-
if(currBitmap != null && mImageView != null && softRefBitmap != null && url.equals(mImageView.getTag())){
-
mImageView.setImageBitmap(softRefBitmap);
-
}
-
//软引用中没有,从文件中拿数据
-
else if(bitmap != null && mImageView != null && url.equals(mImageView.getTag())){
-
mImageView.setImageBitmap(bitmap);
-
}
-
//文件中也没有,此时根据mImageView的tag,即url去判断该url对应的task是否已经在执行,如果在执行,本次操作不创建新的线程,否则创建新的线程。
-
else if(url != null && needCreateNewTask(mImageView)){
-
MyAsyncTask task = new MyAsyncTask(url, mImageView, path,mActivity,download);
-
if(mImageView != null){
-
Log.i(TAG, "执行MyAsyncTask --> " + Util.flag);
-
Util.flag ++;
-
task.execute();
-
//将对应的url对应的任务存起来
-
map.put(url, task);
-
}
-
}
-
}
-
/**
-
* 判断是否需要重新创建线程下载图片,如果需要,返回值为true。
-
* @param url
-
* @param mImageView
-
* @return
-
*/
-
private boolean needCreateNewTask(ImageView mImageView){
-
boolean b = true;
-
if(mImageView != null){
-
String curr_task_url = (String)mImageView.getTag();
-
if(isTasksContains(curr_task_url)){
-
b = false;
-
}
-
}
-
return b;
-
}
-
/**
-
* 检查该url(最终反映的是当前的ImageView的tag,tag会根据position的不同而不同)对应的task是否存在
-
* @param url
-
* @return
-
*/
-
private boolean isTasksContains(String url){
-
boolean b = false;
-
if(map != null && map.get(url) != null){
-
b = true;
-
}
-
return b;
-
}
-
/**
-
* 删除map中该url的信息,这一步很重要,不然MyAsyncTask的引用会“一直”存在于map中
-
* @param url
-
*/
-
private void removeTaskFormMap(String url){
-
if(url != null && map != null && map.get(url) != null){
-
map.remove(url);
-
System.out.println(“当前map的大小==”+map.size());
-
}
-
}
-
/**
-
* 从文件中拿图片
-
* @param mActivity
-
* @param imageName 图片名字
-
* @param path 图片路径
-
* @return
-
*/
-
private Bitmap getBitmapFromFile(Activity mActivity,String imageName,String path){
-
Bitmap bitmap = null;
-
if(imageName != null){
-
File file = null;
-
String real_path = “”;
-
try {
-
if(Util.getInstance().hasSDCard()){
-
real_path = Util.getInstance().getExtPath() + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}else{
-
real_path = Util.getInstance().getPackagePath(mActivity) + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}
-
file = new File(real_path, imageName);
-
if(file.exists())
-
bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
-
} catch (Exception e) {
-
e.printStackTrace();
-
bitmap = null;
-
}
-
}
-
return bitmap;
-
}
-
/**
-
* 将下载好的图片存放到文件中
-
* @param path 图片路径
-
* @param mActivity
-
* @param imageName 图片名字
-
* @param bitmap 图片
-
* @return
-
*/
-
private boolean setBitmapToFile(String path,Activity mActivity,String imageName,Bitmap bitmap){
-
File file = null;
-
String real_path = “”;
-
try {
-
if(Util.getInstance().hasSDCard()){
-
real_path = Util.getInstance().getExtPath() + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}else{
-
real_path = Util.getInstance().getPackagePath(mActivity) + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}
-
file = new File(real_path, imageName);
-
if(!file.exists()){
-
File file2 = new File(real_path + “/”);
-
file2.mkdirs();
-
}
-
file.createNewFile();
-
FileOutputStream fos = null;
-
if(Util.getInstance().hasSDCard()){
-
fos = new FileOutputStream(file);
-
}else{
-
fos = mActivity.openFileOutput(imageName, Context.MODE_PRIVATE);
-
}
-
if (imageName != null && (imageName.contains(“.png”) || imageName.contains(“.PNG”))){
-
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
-
}
-
else{
-
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
-
}
-
fos.flush();
-
if(fos != null){
-
fos.close();
-
}
-
return true;
-
} catch (Exception e) {
-
e.printStackTrace();
-
return false;
-
}
-
}
-
/**
-
* 辅助方法,一般不调用
-
* @param path
-
* @param mActivity
-
* @param imageName
-
*/
-
private void removeBitmapFromFile(String path,Activity mActivity,String imageName){
-
File file = null;
-
String real_path = “”;
-
try {
-
if(Util.getInstance().hasSDCard()){
-
real_path = Util.getInstance().getExtPath() + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}else{
-
real_path = Util.getInstance().getPackagePath(mActivity) + (path != null && path.startsWith(“/”) ? path : “/” + path);
-
}
-
file = new File(real_path, imageName);
-
if(file != null)
-
file.delete();
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 异步下载图片的方法
-
* @author yanbin
-
*
-
*/
-
private class MyAsyncTask extends AsyncTask<String, Void, Bitmap>{
-
private ImageView mImageView;
-
private String url;
-
private OnImageDownload download;
-
private String path;
-
private Activity mActivity;
-
public MyAsyncTask(String url,ImageView mImageView,String path,Activity mActivity,OnImageDownload download){
-
this.mImageView = mImageView;
-
this.url = url;
-
this.path = path;
-
this.mActivity = mActivity;
-
this.download = download;
-
}
-
@Override
-
protected Bitmap doInBackground(String… params) {
-
Bitmap data = null;
-
if(url != null){
-
try {
-
URL c_url = new URL(url);
-
InputStream bitmap_data = c_url.openStream();
-
data = BitmapFactory.decodeStream(bitmap_data);
-
String imageName = Util.getInstance().getImageName(url);
-
if(!setBitmapToFile(path,mActivity,imageName, data)){
-
removeBitmapFromFile(path,mActivity,imageName);
-
}
-
imageCaches.put(url, new SoftReference(data.createScaledBitmap(data, 100, 100, true)));
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
总结
现在新技术层出不穷,如果每次出新的技术,我们都深入的研究的话,很容易分散精力。新的技术可能很久之后我们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。
我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。
Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。
如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。
(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
[外链图片转存中…(img-MF2zuigv-1713785339533)]
总结
现在新技术层出不穷,如果每次出新的技术,我们都深入的研究的话,很容易分散精力。新的技术可能很久之后我们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。
我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。
Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。
如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。
(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)
[外链图片转存中…(img-PqoBzUnr-1713785339535)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!