安卓开发之Picasso框架的使用例子

 更新时间:2016年9月20日 19:53  点击:1664
安卓开发之Picasso框架了解不多了,小编今天来为各位介绍两个关于安卓开发之Picasso框架例子,希望这两个例子能够帮助到各位。

之前一直使用imageloader这个框架加载图片,觉得配置很麻烦,觉得使用Picasso这个框架。

什么是Picasso我就不多说了,大家可以去官网看,http://square.github.io/picasso/。

Picasso使用的方法汇总:

 代码如下 复制代码


Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Picasso.with(context).load(url).into(view);
Picasso.with(context).load(url) .resize(50, 50).centerCrop().into(imageView)
//这里的placeholder将resource传入通过getResource.getDrawable取资源,所以可以是张图片也可以是color id
Picasso.with(context).load(url).placeholder(R.drawable.user_placeholder).error(R.drawable.user_placeholder_error).into
 
(imageView);
 
Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);
Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2);
Picasso.with(context).load(new File(...)).into(imageView3);
//这里显示notification的图片
Picasso.with(activity).load(Data.URLS[new Random().nextInt(Data.URLS.length)]).resizeDimen
 
(R.dimen.notification_icon_width_height,R.dimen.notification_icon_width_height).into(remoteViews, R.id.photo,
 
NOTIFICATION_ID, notification);
//这里是通过设置tag标签,就是当前传过来的context,这样就可以根据这个context tag来pause和resume显示了
Picasso.with(context).load(url).placeholder(R.drawable.placeholder).error(R.drawable.error).fit().tag(context).into
 
(view);
//监听onScrollStateChanged的时候调用执行
picasso.resumeTag(context);
picasso.pauseTag(context);
 
Picasso.with(context).load(contactUri).placeholder(R.drawable.contact_picture_placeholder).tag(context).into
 
(holder.icon);
//这个onpause方法里的这段代码还是很有意思的
@Override protected void onPause() {
    super.onPause();
    if (isFinishing()) {
      // Always cancel the request here, this is safe to call even if the image has been loaded.
      // This ensures that the anonymous callback we have does not prevent the activity from
      // being garbage collected. It also prevents our callback from getting invoked even after the
      // activity has finished.
      Picasso.with(this).cancelRequest(imageView);
    }
  }
// Trigger the download of the URL asynchronously into the image view.
    Picasso.with(context)
        .load(url)
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.error)
        .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size)
        .centerInside()
        .tag(context)
        .into(holder.image);
//Picasso.with使用的是单例模式

Picasso.with(this).cancelTag(this);

然后呢,Picasso还提供了debug的标示,调用picasso的setIndicatorsEnabled方法,true是debug模式,跟踪代码其实就是在最后生成的
PicassoDrawable类的ondraw里绘制了个左上角小三角,根据

 代码如下 复制代码

public enum LoadedFrom {
MEMORY(Color.GREEN),
DISK(Color.BLUE),
NETWORK(Color.RED);

枚举里的不同值标示不同加载来源,这对分析图片加载有好处。

在Picasso.with()的时候会将执行所需的所有必备元素创建出来,如缓存cache、执行executorService、调度dispatch等,在load()时创建Request,在into()中创建action、bitmapHunter,并最终交给dispatcher执行。


Picasso创建圆形图像

上篇介绍了Picasso这个框架,git地址是https://github.com/square/picasso。怎么实现各种各样的图片样式呢,在Picasso里提供了Transformation这个接口,我们可以自己实现。下面是一个实现圆形图片的demo;

 代码如下 复制代码

public class CircleTransform implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
 
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
 
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
 
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
 
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
 
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
 
squaredBitmap.recycle();
return bitmap;
}
 
@Override
public String key() {
return "circle";
}
}

使用它:

Picasso.with(activity).load(mayorShipImageLink).transform(new CircleTransform()).into(ImageView);
 

Activity中经常会要做到返回顶部或一些功能了,今天我们就一起来看一个关于Android开发之Activity的中部或底部回到顶部的例子,具体操作如下.

我们浏览淘宝商品详情的时候会遇到回到顶部这个功能,下面就说说这个功能的简单实现


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="@+id/sc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<WebView
android:id="@+id/wb"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</WebView>
</LinearLayout>
</ScrollView>
 
<Button
android:id="@+id/bt"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/black"
android:layout_gravity="bottom"
android:text="点我向上"
android:textColor="#ffffff"
/>
 
</FrameLayout>

布局最外层使用FrameLayout,然后套上ScrollView,但是一定要注意ScrollView的高只能是wrap_content,要不然点击回到底部没效果。

代码如下

public class MainActivity extends AppCompatActivity {
private ScrollView sc;
private WebView wb;
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sc=(ScrollView)findViewById(R.id.sc);
wb=(WebView)findViewById(R.id.wb);
bt=(Button)findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sc.post(new Runnable() {
@Override
public void run() {
sc.post(new Runnable() {
public void run() {
// 回到顶部
sc.fullScroll(ScrollView.FOCUS_UP);
}
});
}
});
}
});
initView();
}
 
private void initView() {
String url = "https://www.111cn.net/";
WebSettings webSettings = wb.getSettings();
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webSettings.setJavaScriptEnabled(true); //设置WebView属性执行Javascript脚本
//设置可以访问文件
webSettings.setAllowFileAccess(true);
webSettings.setBuiltInZoomControls(false);// 设置是否显示缩放工具
wb.loadUrl(url);
wb.setWebViewClient(new WebViewClient());
 
}
}


2015-12-10_164558

实现效果如图,我这里是使用webView链接百度的网页,换成其他的控件也是一样的

下面我们一起来看一篇关于android studio、eclipse分别导入运行qq Android sdk 第三方登录的例子,希望此例子能够帮助到大家。

这里我是先导入eclipse,然后到处为gradle buid files ,再导入 android studio。
 
要是对gradle编译脚本熟悉的,可以直接导入,然后手动写gradle的配置文件。

1.下载qq android sdk

选择:

1.jpg

2. 解压后得到的目录结构为:

1.jpg

3.将上面的sample文件夹导入的Eclipse,目录结构如下:

1.jpg

修改项目的编码为UTF-8:

1.jpg

4.修复库依赖关系

 代码显示有错误,那是因为我们没有将qq的sdk jar包放到libs目录下。

点击项目右键&mdash;&mdash;Properities&mdash;&mdash;Android,将错误的依赖关系删除:

1.jpg

5.导入sdk jar库

将下载的qq android sdk包下的 jar/目录下的 两个jar包 复制到 项目的libs目录:

1.jpg

 

此时项目的目录结构如下:

1.jpg

然后clean  ,再重新编译。代码就没有报错了。

6.将项目导入到Android studio

最关键的一步,如何将eclipse中的项目导入到Android studio中:

右键项目,选择&ldquo;export&rdquo;&mdash;&mdash;android&mdash;&mdash;generate gradle build files &mdash;&mdash;然后选中要到处都项目,得到导出的项目包。

再将得到的项目包,导入到android studio中。会提示报错,我们需要将项目根目录的build.gradle文件中的(可能你的android studio使用的gradle版本和gradle插件版本与我的有不同,建议更改成自己的所使用的版本)


dependencies {
    classpath 'com.android.tools.build:gradle:0.12+'
}
改为我们使用的新到gradle插件版本:


dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}

注意:如果有可能,可能还需要改项目根目录下/gradle/wrapper/gradle-wrapper.properties中的

7.重新编译运行

改完后,点击&ldquo;Sync now&rdquo;,重新编译项目,就会发现项目没有报错,在模拟器中测试,一切正常。
android studio版本的QQ sdk demo下载(最新版)

下面我们来为各位以图文的形式给各位介绍一篇关于android studio、eclipse分别导入新浪微博 Android sdk 第三方登录demo的例子。
1.下载解压sdk
先下载weibo android sdk 包:
打开网址:https://github.com/sinaweibosdk/weibo_android_sdk
将sdk下载到本地,解压后的目录结构:
点击进入“demo-src”目录,结构如下:
将上面的两个项目都导入到eclipse中!!
2.导demo到eclipse
分别修改两个项目的文件编码为UTF-8,保存。
3.修改 debug.keystore
MD5 工具是根据 keystore 来生成签名的,丌同的 keystore 生成的签名是丌一样的。此 Demo 的签名是用官网提
供的 keystore 生成的,若要顺利运行 Demo 程序,需要?行设置戒是替换 keystore,两种方法选择一种操作即可:
方式一:替换 keystore:把 Android 默认的 debug.keystore(在 C:\Users\XXXXX\.android 目录下)替换成官
方在 GitHub 上提供的 debug.keystore。
方式二:在 Eclipse 中设置工程 keystore:在 Eclipse 中点击“WindowsPreferencesAndroidBuild”,在
Custom debug keystore 中选择 Demo 中的 debug.keystore,如下图,点击 ApplyOK,Demo 即可正常运行。
注意:这一步是必须的,如果没有替换,demo 程序在运行时将无法正确的授权成功。用户在替换前,最好先备份
一下原始的 debug.keystore。GitHub 中 debug.keysotre 是新浪官方的,除了编译运行官方 DEMO 外,丌要直
接使用它,出于安全的考虑,用户应该为自己的应用提供一份 keysotre。 
 
4.修复依赖
如果修改完编码后,eclipse仍然显示报错,那么就要去看看是否是项目的依赖出了问题:
选中WeiboSDKdemo后鼠标右键单击——Properties——android——Add,如下图,将WeiboSDK添加为WeiboSDKdemo的依赖项目。(如果没有显示红色的问号,那么说明依赖没有问题)
5.将项目导入到Android studio
最关键的一步,如何将eclipse中的项目导入到Android studio中:
右键项目,选择“export”——android——generate gradle build files ——然后选中要到处都项目,得到导出的项目包。

再将得到的项目包,导入到android studio中。会提示报错,我们需要将项目根目录的build.gradle文件中的(可能你的android studio使用的gradle版本和gradle插件版本与我的有不同,建议更改成自己的所使用的版本):


dependencies {
    classpath 'com.android.tools.build:gradle:0.12+'
}

改为我们使用的新到gradle插件版本:

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}

注意:如果有可能,可能还需要改项目根目录下/gradle/wrapper/gradle-wrapper.properties中的

 

6.重新编译运行
改完后,点击“Sync now”,重新编译项目,就会发现项目没有报错,在模拟器中测试,一切正常。
,代码就编译通过,然后在安卓模拟器中运行。如下图:
===================================
问题是,一切没有这么顺利,应为android studio使用的是gradle来编译的。而gradle编译成功的要求要严格一些,你会发现新浪微博的sdk demo运行后会报好几种错误:
错误A:
Error:The project is using an unsupported version of the Android Gradle plug-in (0.12.2). The recommended version is 1.5.0.
Fix plugin version and sync project

解决办法:把demo-src目录下的build.gradle中的gradle插件版本改成你android studio所使用的版本(我使用的是1.5.0):


Java
dependencies {
    classpath 'com.android.tools.build:gradle:1.5.0'
}
123 dependencies {    classpath 'com.android.tools.build:gradle:1.5.0'}

 

把demo-src/gradle/wrapper/gradle-wrapper.properties中的gradle版本改成android studio所使用的版本(我是用的最新的gradle版本,2.8):
Java
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
1 distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip

 

然后”sync now”,就不会报这个错误了。
 
错误B:
这个错误是因为新浪weibo的sdk开发人员偷懒导致的,出错的原因都是在图片的 问题上,所以,我这里将其归为一种错误。
错误如下:
Error:Execution failed for task ‘:WeiboSDKDemo:mergeDebugResources’.
> Crunching Cruncher ic_login_button_blue_normal.9.png failed, see logs
其实,看编译错误,还是要看gradle console里的错误和警告,如下:
AAPT err(Facade for 1170324693): ERROR: 9-patch image C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\res\drawable\ic_login_button_blue_normal.9.png malformed.
AAPT err(Facade for 1170324693):        Frame pixels must be either solid or transparent (not intermediate alphas).
AAPT err(Facade for 1170324693):        Found at pixel #2 along top edge.
AAPT err(Facade for 1170324693): ERROR: 9-patch image C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\res\drawable\ic_login_button_blue_focused.9.png malformed.
AAPT err(Facade for 1170324693):        Frame pixels must be either solid or transparent (not intermediate alphas).
AAPT err(Facade for 1170324693):        Found at pixel #2 along top edge.
AAPT err(Facade for 576922613): libpng error: Not a PNG file
AAPT err(Facade for 735358242): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-mdpi-v4\ic_com_sina_weibo_sdk_login_with_text.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 576922613): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-hdpi-v4\ic_com_sina_weibo_sdk_logo.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 735358242): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-ldpi-v4\ic_com_sina_weibo_sdk_logo.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 576922613): ERROR: 9-patch image C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\res\drawable\ic_login_button_blue_pressed.9.png malformed.
AAPT err(Facade for 706899532): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-xhdpi-v4\ic_com_sina_weibo_sdk_logo.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 576922613):        No marked region found along edge.
AAPT err(Facade for 576922613):        Found along top edge.
AAPT err(Facade for 1615154168): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-ldpi-v4\ic_com_sina_weibo_sdk_login_with_text.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 1561367387): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-mdpi-v4\ic_com_sina_weibo_sdk_logo.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
AAPT err(Facade for 1561367387): C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\build\intermediates\exploded-aar\demo-src\WeiboSDK\unspecified\res\drawable-hdpi-v4\ic_com_sina_weibo_sdk_login_with_text.png: libpng warning: iCCP: Not recognizing known sRGB profile that has been edited
上面的错误主要是两种(这里我忽略警告信息,因为警告不会导致编译失败。警告信息其实也是因为png的图片有问题,大家可以自行google原因和解决方法。):
1.AAPT err(Facade for 1170324693): ERROR: 9-patch image C:\Users\AlexY\Desktop\weibo_android_sdk-master\demo-src\WeiboSDKDemo\res\drawable\ic_login_button_blue_normal.9.png malformed.
AAPT err(Facade for 1170324693):        Frame pixels must be either solid or transparent (not intermediate alphas).
AAPT err(Facade for 1170324693):        Found at pixel #2 along top edge.
原因:报这个错,是因为WeiboSDKDemo中的图片有部分其实不是点9图片,只不过是改了后缀名。而前面说过,gradle编译要求高些,所以在eclipse中不会因为这个错误而编译失败,但是android studio却会导致失败。
解决办法:将所以提示不是点9图片的文件,使用android studio的点9图片编辑器,将其修复成点9图片。
2.AAPT err(Facade for 576922613): libpng error: Not a PNG file
原因:这个错误是因为,WeiboSDKDemo中的图片里有图片不是png格式的图片,而是jpg格式的图片,只不过是被新浪的开发人员的直接改成了 “.png”的后缀名,所以,android studio编译不通过。
解决办法:找到那个不是png格式的图片,windows系统貌似没有这个工具,即使是右键查看文件属性也是看不出的。所以,只能借助android studio的图片编辑器了,用android studio依次打开所有的.png文件,最终发现:/demo-src/WeiboSDKDemo/res/drawable/ic_share_music_thumb.png 并不是png格式的,而是jpg

 

然后将其转换为png图片即可。
错误C:
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat$AccessibilityServiceInfoVersionImpl;
at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:579)
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:535)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:517)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:164)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:504)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:334)
at com.android.dx.command.dexer.Main.run(Main.java:277)
at com.android.dx.command.dexer.Main.main(Main.java:245)
at com.android.dx.command.Main.main(Main.java:106)
原因:是因为WeiboSDKDemo/build.gradle文件中的添加了两次WeiboSDK依赖,如下:

 


dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile project(':WeiboSDK')
    compile project(':WeiboSDK')
}


而WeiboSDK/libs下有support-v4.jar,所以导致提示support-v4包多次导入,导致编译失败。
解决办法:删除重复的一行,该称下面的样子:

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile project(':WeiboSDK')
    
}


接着”sync now”,重新编译,就不会报这个错误了。

很多APP应用喜欢在首屏显示大广告效果,这样可以在启动APP还没连上网络时不会显示那么空白,还可以增加广告效果。本文我们来分享一下这样子的功能在Android开发中如何实现。

本文我们分享一个Android APP 首屏广告示例, 这里我们主要讲的是实现原理及一些页面的架构,代码只能作参考。

广告需求图:

广告需求图



1. 显示本地存储广告图片, 点击图片, 跳转广告链接, 并提供微信分享功能.
2. 异步下载广告信息, 提高启动速度; 异步下载并保存广告和分享图片, 提高加载速度.

开发过程中, 使用了一些小技巧, 我会详细讲解注意的要点, 包括:
(1) 使用RxAndroid库, 在新线程上做异步下载广告信息.
(2) 使用Picasso库, 异步下载图片(Bitmap)并存储至本地.
(3) 使用原生Handler类, 实现计时器功能, 按秒跳转数字.
(4) 使用WebView视图, 加载广告链接, 并提供分享功能.

1. 下载广告

在欢迎页面中, 启动一个异步线程, 加载广告信息, 提高启动速度, 防止网速过慢导致切换卡顿.

// 异步广告信息
private void AsyncCheckInfo() {
    // 异步线程处理监听, 在新线程上监听, 发送到主线程
    Observableobservable = Observable.create(new Observable.OnSubscribe() {
        @Override
        public void call(Subscriber subscriber) {
            subscriber.onNext(checkInfo());
            subscriber.onCompleted();
        }
    }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());

    // 成功回调
    observable.subscribe(new Subscriber() {
        @Override
        public void onCompleted() {
            Log.i(TAG, "onCompleted");
        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onNext(String s) {
            Log.i(TAG, "onNext");
        }
    });
}

在新线程(newThread)中加载, 完成后发送到主线程(mainThread). 参考.

判断网络, 在有网的时候, 加载广告信息; 在无网的时候, 直接略过.

// 加载广告信息
public String checkInfo() {
    if (NetUtils.isNetworkConnected(ChunyuApp.getAppContext())) {
        UpdateUtils.checkDailyInfo(WelcomeActivity.this, mDailyRequestCallback);
        return "Begin to load info.";
    } else {
        return "Stop to load info";
    }
}

在UpdateUtils.checkDailyInfo中, 解析广告请求的返回值. 如果包含广告信息, 则存储在首选项(SharedPreference)中, 下次启动广告直接读取; 如果不包含广告信息, 则设置无数据标记, 在使用时判定无广告.
最后调用回调接口mDailyRequestCallback继续处理.

ArrayListadverts = version.advert;
if (adverts.size() > 0) {
    for (int i = 0; i < adverts.size(); ++i) {
        Advert advert = adverts.get(i);
        if (advert.Number == 1) { // Number等于0是广告
            PedometerAdManager.getInstance().init(advert);
        }
    }
} else {
    Log.e(TAG, "广告是空");
    SharedPreferences sp =
            PreferenceManager.getDefaultSharedPreferences(ChunyuApp.getAppContext());
    sp.edit().putBoolean(WelcomeActivity.FIRST_AD_IS_HAVE_PREFS, false).apply();
}


2. 存储图片

已经存储广告信息之后, 即可获得图片下载链接, 为了提高显示速度, 下载图片存储在本地. 因为下载属于网络请求, 需要异步处理, 本文使用Picasso库, 没有发明轮子.

// 日常信息回调
private final UpdateUtils.DailyRequestCallback mDailyRequestCallback
        = new UpdateUtils.DailyRequestCallback() {
    @Override
    public void operationExecutedSuccess() {
        if (mAdManager.getImageUrl() != null && !mAdManager.getImageUrl().isEmpty())
            Picasso.with(WelcomeActivity.this).
                    load(mAdManager.getImageUrl()).into(mAdImageTarget);

        if (mAdManager.getShareIcon() != null && !mAdManager.getShareIcon().isEmpty())
            Picasso.with(WelcomeActivity.this).
                    load(mAdManager.getShareIcon()).into(mAdShareImageTarget);
    }

    @Override
    public void operationExecutedFailed() {
        Log.e(TAG, "operationExecutedFailed");
    }
};

// 广告图片
private Target mAdImageTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        String path = FileUtility.savePic(bitmap);
        mPrefs.edit().putString(FIRST_AD_PATH_PREFS, path).apply();
    }

    @Override public void onBitmapFailed(Drawable errorDrawable) {

    }

    @Override public void onPrepareLoad(Drawable placeHolderDrawable) {

    }
};

// 分享Icon
private Target mAdShareImageTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        String path = FileUtility.savePic(bitmap);
        mPrefs.edit().putString(FIRST_AD_SHARE_IMAGE_URL_PREFS, path).apply();
    }

    @Override public void onBitmapFailed(Drawable errorDrawable) {
    }

    @Override public void onPrepareLoad(Drawable placeHolderDrawable) {

    }
};

在页面暂停时, 移除Picasso的请求线程.

@Override
protected void onPause() {
    MobclickAgent.onPause(this);
    handler.removeCallbacks(runnable); // 停止
    Picasso.with(this).cancelRequest(mAdImageTarget); // 停止
    Picasso.with(this).cancelRequest(mAdShareImageTarget); // 停止
    super.onPause();
}

注意: 在Picasso中, Target是和ImageView控件弱绑定, 在销毁ImageView时, 会随之销毁. 如果未提供ImageView控件, 需要手动销毁请求, 如在onPause中取消. 否则会出现下载异常. 参考.

3. 显示广告

首先Logo页显示LOGO_TIME秒, 再判断显示引导(首次启动)或显示广告.
显示广告是使用存储在首选项(SharedPreference)中的数据, 图片使用本地资源解析, 提高显示速度.

// 显示启动信息
private void showLaunchInfo() {
    // 显示一段时间的主屏Logo
    new Handler().postDelayed(this::showAdInfo, LOGO_TIME);
}

// 显示广告信息
private void showAdInfo() {
    // 判断是否有广告
    if (mPrefs.getBoolean(FIRST_AD_IS_HAVE_PREFS, false)) {
        Log.e(TAG, "包含广告");
        String path = mPrefs.getString(FIRST_AD_PATH_PREFS, "");
        if (!path.isEmpty()) {
            int time = mPrefs.getInt(FIRST_AD_TIME_PREFS, 0);
            Bitmap bitmap = BitmapFactory.decodeFile(path);
            Log.e(TAG, "time: " + time);
            showAdImage(bitmap, time);
            if (!NetUtils.isNetworkConnected(ChunyuApp.getAppContext())) {
                mIvWebImage.setClickable(false);
            }
        } else {
            gotoOtherActivity();
        }
    } else {
        gotoOtherActivity();
    }
}


显示的广告使用上次网络请求的存储数据, 也可能是本次网络请求的, 主要取决于在LOGO_TIME时间中, 是否下载完成启动信息, 并存储至本地.

4. 广告计时器

在广告图片显示时, 提供倒计时器, 按秒跳时, 提供跳过按钮直接跳过广告.

// 显示广告
private void showAdImage(Bitmap bitmap, int time) {
    mIvWebImage.setVisibility(View.VISIBLE);
    mTvSkip.setVisibility(View.VISIBLE);
    mTvSkip.setOnClickListener(v -> gotoOtherActivity());
    mIvBackground.setVisibility(View.INVISIBLE);
    mIvFirstLogo.setVisibility(View.INVISIBLE);

    mIvWebImage.setImageBitmap(bitmap);
    mAdTime = time + 2;
    handler.post(runnable); // 设置读秒
}

// 设置读秒器
private int s = 0; // 时间Delay
private final Handler handler = new Handler();
private final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // handler自带方法实现定时器
        try {
            handler.postDelayed(this, 1000);

            if (s < 1) {
                s++;
                return;
            }

            if (s <= (mAdTime - 1)) {
                mTvSkip.setText(String.valueOf("跳过\n"
                        + Integer.toString((mAdTime - 1) - (s++)) + "秒"));
            }

            // 计时器为0时, 开始跳转
            if (s == mAdTime) {
                gotoOtherActivity();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};

广告时间额外显示两秒, 提供页面跳转间隔, 前一秒后一秒, 保证广告时间充足.

在广告页跳转或页面结束时, 删除计时回调.

// 跳转到现实广告的视图
public void gotoShowAdView(View view) {
    NV.o(this, AdvertisementActivity.class);
    handler.removeCallbacks(runnable);
    finish();
}

@Override
protected void onPause() {
    MobclickAgent.onPause(this);
    handler.removeCallbacks(runnable); // 停止
    Picasso.with(this).cancelRequest(mAdImageTarget); // 停止
    Picasso.with(this).cancelRequest(mAdShareImageTarget); // 停止
    super.onPause();
}

本文使用handler类, 循环调用计时, 必须在离开页面时, 清除runnable回调. 否则会遗忘线程泄露内存.

5. 链接页面

点击广告图片, 会跳转至广告链接, 根据参数设置全屏或者提供分享功能, 把链接分享至微信. 微信分享需要标题, 内容, 图标(Icon), 其中图片是从服务器下载后预存在本地.

/**
 * 广告Activity
 *


 * Created by wangchenlong on 15/12/2.
 */
public class AdvertisementActivity extends PActivity {

    @SuppressWarnings("unused")
    private static final String TAG = "DEBUG-WCL: "
            + AdvertisementActivity.class.getSimpleName();

    @Bind(R.id.advertise_pwv_container) PedoWebView mPwvContainer;
    @Bind(R.id.advertise_ll_back_home) LinearLayout mLlBackHome;
    @Bind(R.id.advertise_ll_send_session) LinearLayout mLlSendSession;
    @Bind(R.id.advertise_ll_send_timeline) LinearLayout mLlSendTimeline;
    @Bind(R.id.advertise_ll_action_bar) LinearLayout mLlActionBar;

    private SharedPreferences mPrefs;
    private int mFlag; // 判断分享地点

    private static final int WECHAT_SESSION = 0;    // 微信对话
    private static final int WECHAT_TIMELINE = 1;   // 朋友圈

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_advertisement);
        ButterKnife.bind(this);

        mPrefs = PreferenceManager.getDefaultSharedPreferences(ChunyuApp.getAppContext());

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null)
            actionBar.setDisplayHomeAsUpEnabled(true);

        // 是否全屏
        if (mPrefs.getBoolean(WelcomeActivity.FIRST_AD_IS_FULL_PREFS, false)) {
            mLlActionBar.setVisibility(View.GONE);
        } else {
            mLlBackHome.setOnClickListener(v -> {
                NV.o(this, PedometerActivity.class);
                finish();
            });

            // 是否分享
            if (mPrefs.getBoolean(WelcomeActivity.FIRST_AD_IS_SHARE_PREFS, false)) {
                mLlSendSession.setOnClickListener(v -> {
                    mFlag = WECHAT_SESSION;
                    shareWechat();
                });
                mLlSendTimeline.setOnClickListener(v -> {
                    mFlag = WECHAT_TIMELINE;
                    shareWechat();
                });
            } else {
                mLlSendSession.setVisibility(View.GONE);
                mLlSendTimeline.setVisibility(View.GONE);
            }
        }

        mPwvContainer.loadUrl(mPrefs.getString(WelcomeActivity.FIRST_AD_URL_PREFS, ""));
    }

    // 分享到微信
    public void shareWechat() {
        IWXAPI wxapi =
                WXAPIFactory.createWXAPI(ChunyuApp.getAppContext(), SNSConst.WX_APP_ID_ONLINE, true);
        wxapi.registerApp(SNSConst.WX_APP_ID_ONLINE);

        WXWebpageObject webpage = new WXWebpageObject();
        webpage.webpageUrl = mPrefs.getString(WelcomeActivity.FIRST_AD_URL_PREFS, "");
        WXMediaMessage msg = new WXMediaMessage(webpage);
        msg.title = mPrefs.getString(WelcomeActivity.FIRST_AD_SHARE_TITLE_PREFS, "");
        msg.description = mPrefs.getString(WelcomeActivity.FIRST_AD_SHARE_CONTENT_PREFS, "");

        String path = mPrefs.getString(WelcomeActivity.FIRST_AD_SHARE_IMAGE_URL_PREFS, "");
        if (!path.isEmpty()) {
            Bitmap bitmap = BitmapFactory.decodeFile(path);
            if (bitmap != null) {
                msg.setThumbImage(bitmap);
            } else {
                msg.setThumbImage(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
            }
            SendMessageToWX.Req req = new SendMessageToWX.Req();
            req.transaction = String.valueOf(System.currentTimeMillis());
            req.message = msg;
            req.scene = ((mFlag == 0) ?
                    SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline);
            wxapi.sendReq(req);
        }
    }

    @Override public void onBackPressed() {
        if (mPwvContainer.canGoBack()) {
            mPwvContainer.goBack();
        } else {
            NV.o(this, PedometerActivity.class);
            finish();
        }
    }
}

调用后退按钮(onBackPressed): 在网页跳转多页时, 返回上一页; 在首页时, 退出广告页面, 跳转主页. 微信分享的图标(Icon), 最好使用方形全图, 否则透明部分会被黑色替代, 服务器提供图片时需要注意.



[!--infotagslink--]

相关文章

  • 苹果告别“高大上”,越来越向安卓和中国用户靠近

    “一起,让我们将这个世界变得更好。”苹果首席执行官蒂姆 库克对着台下5000多名开发者说道,声音略有些沙哑和颤抖。...2016-07-04
  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • ps怎么使用HSL面板

    ps软件是现在很多人都会使用到的,HSL面板在ps软件中又有着非常独特的作用。这次文章就给大家介绍下ps怎么使用HSL面板,还不知道使用方法的下面一起来看看。 &#8195;...2017-07-06
  • 基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍

    这篇文章主要介绍了基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍 的相关资料,需要的朋友可以参考下...2016-05-14
  • Plesk控制面板新手使用手册总结

    许多的朋友对于Plesk控制面板应用不是非常的了解特别是英文版的Plesk控制面板,在这里小编整理了一些关于Plesk控制面板常用的使用方案整理,具体如下。 本文基于Linu...2016-10-10
  • 使用insertAfter()方法在现有元素后添加一个新元素

    复制代码 代码如下: //在现有元素后添加一个新元素 function insertAfter(newElement, targetElement){ var parent = targetElement.parentNode; if (parent.lastChild == targetElement){ parent.appendChild(newEl...2014-05-31
  • 使用GruntJS构建Web程序之构建篇

    大概有如下步骤 新建项目Bejs 新建文件package.json 新建文件Gruntfile.js 命令行执行grunt任务 一、新建项目Bejs源码放在src下,该目录有两个js文件,selector.js和ajax.js。编译后代码放在dest,这个grunt会...2014-06-07
  • 使用percona-toolkit操作MySQL的实用命令小结

    1.pt-archiver 功能介绍: 将mysql数据库中表的记录归档到另外一个表或者文件 用法介绍: pt-archiver [OPTION...] --source DSN --where WHERE 这个工具只是归档旧的数据,不会对线上数据的OLTP查询造成太大影响,你可以将...2015-11-24
  • 如何使用php脚本给html中引用的js和css路径打上版本号

    在搜索引擎中搜索关键字.htaccess 缓存,你可以搜索到很多关于设置网站文件缓存的教程,通过设置可以将css、js等不太经常更新的文件缓存在浏览器端,这样访客每次访问你的网站的时候,浏览器就可以从浏览器的缓存中获取css、...2015-11-24
  • jQuery 1.9使用$.support替代$.browser的使用方法

    jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support 。 在更新的 2.0 版本中,将不再支持 IE 6/7/8。 以后,如果用户需要支持 IE 6/7/8,只能使用 jQuery 1.9。 如果要全面支持 IE,并混合...2014-05-31
  • MySQL日志分析软件mysqlsla的安装和使用教程

    一、下载 mysqlsla [root@localhost tmp]# wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz--19:45:45-- http://hackmysql.com/scripts/mysqlsla-2.03.tar.gzResolving hackmysql.com... 64.13.232.157Conn...2015-11-24
  • 安装和使用percona-toolkit来辅助操作MySQL的基本教程

    一、percona-toolkit简介 percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括: 检查master和slave数据的一致性 有效地对记录进行归档 查找重复的索...2015-11-24
  • C#注释的一些使用方法浅谈

    C#注释的一些使用方法浅谈,需要的朋友可以参考一下...2020-06-25
  • php语言中使用json的技巧及json的实现代码详解

    目前,JSON已经成为最流行的数据交换格式之一,各大网站的API几乎都支持它。我写过一篇《数据类型和JSON格式》,探讨它的设计思想。今天,我想总结一下PHP语言对它的支持,这是开发互联网应用程序(特别是编写API)必须了解的知识...2015-10-30
  • PHP实现无限级分类(不使用递归)

    无限级分类在开发中经常使用,例如:部门结构、文章分类。无限级分类的难点在于“输出”和“查询”,例如 将文章分类输出为<ul>列表形式; 查找分类A下面所有分类包含的文章。1.实现原理 几种常见的实现方法,各有利弊。其中...2015-10-23
  • 安卓开发之设置密码只能输入字母和数字的组合

    设置登录密码我们一般会有限制的如由什么组合了,下面我们来看一篇关于安卓开发之设置密码只能输入字母和数字的组合方法,具体的细节如下所示。 无论是电脑还是手机...2016-09-20
  • php类的使用实例教程

    php类的使用实例教程 <?php /** * Class program for yinghua05-2 * designer :songsong */ class Template { var $tpl_vars; var $tpl_path; var $_deb...2016-11-25
  • 双冒号 ::在PHP中的使用情况

    前几天在百度知道里面看到有人问PHP中双冒号::的用法,当时给他的回答比较简洁因为手机打字不大方便!今天突然想起来,所以在这里总结一下我遇到的双冒号::在PHP中使用的情况!双冒号操作符即作用域限定操作符Scope Resoluti...2015-11-08
  • .net数据库操作框架SqlSugar的简单入门

    这篇文章主要介绍了.net数据库操作框架SqlSugar的简单入门,帮助大家更好的理解和学习使用.net技术,感兴趣的朋友可以了解下...2021-09-22
  • CI框架开发新浪微博登录接口源码完整版

    首先来看下流程:流程原理: 1.通过code获得access_token通过授权,并获取用户的信息(包括用户u_id)(这个u_id在后面的第三方登录表里面叫sina_id,那个表是需要自己建的) 2.查询第三方登录表,如果不存在用户sina_id,分2...2014-05-31