【开源中国Android客户端】源码分析(一) 启动

来源:互联网 发布:私人网络国债基金产品 编辑:程序博客网 时间:2024/05/16 10:34

程序启动第一个界面类: net.oschina.app.AppStart

AppStart负责几件事情
1. 判断是否已经存在AppStart.class实例
2. 判断版本号
3. 展示动画.动画结束后启动LogUploadService然后跳转到MainActivity

  • 利用了动画中的View的渐变动画效果,从半透明到完全不透明,动画持续时间为800ms,动画结束后,完成日志的上传和界面的跳转。
  • 日志上传利用服务在后台完成的,无论上传成功还是失败,最后要记得关掉服务。成功后,将旧的日志文件删除,因为我们要进行新的一轮操作,至于在什么地方会保存日志,后面随着逐步分分析应该会找到它的。此处用到了第三方包https://github.com/loopj/android-async-http.
  • 在onResume函数中做了以下处理:主要是考虑APP版本升级后,当前的版本大于之前的版本,那么就将之前缓存的图片给清理掉,升级后缓存的图片很有可能没有用处了:此处引用了第三方包 http://kjframe.github.io/ 。 (此包确实强大,可惜的是API文档中没有对启动界面引用的preference的API的详细解释,因此本条分析完全是自己揣摩的。至于图片缓存是App中哪一模块用到的,后面随着逐步分分析应该会找到它的。)

原文地址

代码片段解析

@Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 防止第三方跳转时出现双实例        //<1>        Activity aty = AppManager.getActivity(MainActivity.class);        if (aty != null && !aty.isFinishing()) {            finish();        }        // SystemTool.gc(this); //针对性能好的手机使用,加快应用相应速度        //<2>        final View view = View.inflate(this, R.layout.app_start, null);        setContentView(view);        // 渐变展示启动屏        AlphaAnimation aa = new AlphaAnimation(0.5f, 1.0f);        aa.setDuration(800);        view.startAnimation(aa);        //<3>        aa.setAnimationListener(new AnimationListener() {            @Override            public void onAnimationEnd(Animation arg0) {                redirectTo();            }             @Override            public void onAnimationRepeat(Animation animation) {}            @Override            public void onAnimationStart(Animation animation) {}        });    }    @Override    protected void onResume() {        super.onResume();        //<2>        int cacheVersion = PreferenceHelper.readInt(this, "first_install",                "first_install", -1);        int currentVersion = TDevice.getVersionCode();        if (cacheVersion < currentVersion) {            PreferenceHelper.write(this, "first_install", "first_install",                    currentVersion);            cleanImageCache();        }    }    private void cleanImageCache() {        final File folder = FileUtils.getSaveFolder("OSChina/imagecache");        KJAsyncTask.execute(new Runnable() {            @Override            public void run() {                for (File file : folder.listFiles()) {                    file.delete();                }            }        });    }    /**     * 跳转到...     */    private void redirectTo() {        Intent uploadLog = new Intent(this, LogUploadService.class);        //<4>        startService(uploadLog);        Intent intent = new Intent(this, MainActivity.class);        //<5>        startActivity(intent);        finish();    }}

<1>

进入AppManager.class可以发现其实是一个Activity.class实例的管理类.主要负责用栈的方式管理已经存在的Activity实例.
通过AppManager.getActivity(MainActivity.class)查询是否管理类里面是否已经保存MainActivity.class的实例.如果有则将已经存在的实例finish(防止MainActivity.class双实例)

<2>

通过View.inflate(this, R.layout.app_start, null)生成布局view.选择这样想把布局文件生成一个View实例再调用setContentView(View view)设置布局.出于方便给布局设置动画.
后面也能看到给view设置一个渐变动画.动画结束以后调用redirectTo()函数.
R.layout.app_start布局就是一个线性布局.背景图片是一张480*800的图片(*1)

<3>

处理版本因为在eclipse转过As不久.知道在AndroidMainfest.xml文件可以定义versionName和versionCode属性.但是在As有些许改变.在AndroidMainfest.xml文件依然是可以定义这两个属性.但是如果Gradle编译脚本里面也定义这两个属性这已Gradle编译脚本为准.在Gradle编译脚本没有定义的情况下则使用AndroidMainfest.xml文件所定义的versionName和versionCode属性.

android:versionName=""android:versionCode=""

这里写图片描述

这里写图片描述

这里写图片描述

对于第一次运行
if (cacheVersion < currentVersion)为true
把版本号保存到sharedPreference中并且调用cleanImageCache()函数清楚缓存.(下次运行不在清楚缓存,因为cacheVersion 等于 currentVersion)

cleanImageCache()开启一个线程清空OSChina/iprivate void cleanImageCache() {        final File folder = FileUtils.getSaveFolder("OSChina/imagecache");        KJAsyncTask.execute(new Runnable() {            @Override            public void run() {                for (File file : folder.listFiles()) {                    file.delete();                }            }        });    } 

ervice.class服务,
LogUploadService.class设计出来的目的是查看是否有ErrorLog,发现有ErrorLog通过网络向服务器上报ErrorLog信息.(看到这里深深抽一口气.好设计!)

LogUploadService.class服务查看在/目录是否有OSCLog.log文件.有该文件就像服务器发送log的信息.在回调函数里面可以看到成功发送后把log文件删除.没有log文件那么就没LogUploadService.class的事情了.调用stopSelf()结束该service.

public class LogUploadService extends Service {    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        final File log = FileUtils.getSaveFile("OSChina", "OSCLog.log");        String data = null;        try {            FileInputStream inputStream = new FileInputStream(log);            data = StringUtils.toConvertString(inputStream);        } catch (FileNotFoundException e) {            e.printStackTrace();        }        if (!StringUtils.isEmpty(data)) {            OSChinaApi.uploadLog(data, new AsyncHttpResponseHandler() {                @Override                public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {                    log.delete();                    LogUploadService.this.stopSelf();                }                @Override                public void onFailure(int arg0, Header[] arg1, byte[] arg2,                        Throwable arg3) {                    LogUploadService.this.stopSelf();                }            });        } else {            LogUploadService.this.stopSelf();        }        return super.onStartCommand(intent, flags, startId);    }}

<5>

跳转到MainActivity.到这里为止.启动的部分分析就完成了.

注解部分(尚未能解决的问题,留待以后有能力在分析)

  • *1 针对不同分辨率480*800图片怎么适配?
  • *2 调用到kjframeforandroid的文件管理模块和框架多线程模块

2016.1.28 23:59
对于注解一的解答:
根本就没有适配!!!,把软件作者火蚁在开源中国上的个人空间翻了底朝天,无意中看见了一条他对提问者的回答,结果是这样的:
这里写图片描述
http://www.oschina.net/question/1433975_243063

0 0
原创粉丝点击