开源中国android端版本号:2.4

启动界面:

在AndroidManifest.xml中找到程序的入口,

<activity
android:name=".AppStart"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppStartLoad" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

屏幕方向设置为竖屏,主题为AppStartLoad,关于它的定义如下:

<style name="Theme.AppStartLoad" parent="android:Theme.Black.NoTitleBar.Fullscreen">
<item name="android:windowBackground">@drawable/welcome</item>
<item name="android:windowNoTitle">true</item>
</style>

welcome.png就是启动页显示的图片,填充了整个屏幕。

AppStart.java文件:

package net.oschina.app;
import java.io.File;
import net.oschina.app.ui.MainActivity;
import net.oschina.app.util.TDevice;
import org.kymjs.kjframe.http.KJAsyncTask;
import org.kymjs.kjframe.utils.FileUtils;
import org.kymjs.kjframe.utils.PreferenceHelper;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
/**
* 应用启动界面
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年12月22日 上午11:51:56
*
*/
public class AppStart extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 防止第三方跳转时出现双实例
Activity aty = AppManager.getActivity(MainActivity.class);
if (aty != null && !aty.isFinishing()) {
finish();
}
// SystemTool.gc(this); //针对性能好的手机使用,加快应用相应速度
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);
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();
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);
startService(uploadLog);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}

AppManager.java文件:

package net.oschina.app;
import java.util.Stack;
import android.app.Activity;
import android.content.Context;
/**
* activity堆栈式管理
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月30日 下午6:22:05
*
*/
public class AppManager {
private static Stack<Activity> activityStack;
private static AppManager instance;
private AppManager() {}
/**
* 单一实例
*/
public static AppManager getAppManager() {
if (instance == null) {
instance = new AppManager();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
if (activityStack == null) {
activityStack = new Stack<Activity>();
}
activityStack.add(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity currentActivity() {
Activity activity = activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity(堆栈中最后一个压入的)
*/
public void finishActivity() {
Activity activity = activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null && !activity.isFinishing()) {
activityStack.remove(activity);
activity.finish();
activity = null;
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class<?> cls) {
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
break;
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0, size = activityStack.size(); i < size; i++) {
if (null != activityStack.get(i)) {
//finishActivity方法中的activity.isFinishing()方法会导致某些activity无法销毁
//貌似跳转的时候最后一个activity 是finishing状态,所以没有执行
//内部实现不是很清楚,但是实测结果如此,使用下面代码则没有问题
// find by TopJohn
//finishActivity(activityStack.get(i));
activityStack.get(i).finish();
//break;
}
}
activityStack.clear();
}
/**
* 获取指定的Activity
*
* @author kymjs
*/
public static Activity getActivity(Class<?> cls) {
if (activityStack != null)
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
return activity;
}
}
return null;
}
/**
* 退出应用程序
*/
public void AppExit(Context context) {
try {
finishAllActivity();
// 杀死该应用进程
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Exception e) {
}
}
}

在上面onResume方法中,(这里单独拿出来),逻辑是更新版本号,查看当前安装的apk的版本号,与shared_prefs目录下first_install.xml文件中key为“first_install”对应的value的值的关系。

@Override
protected void onResume() {
super.onResume();
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();
}
}

first_install.xml

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="first_install" value="48" />
</map>

TDevice文件下的getVersionCode()方法:

public static int getVersionCode() {
int versionCode = 0;
try {
versionCode = BaseApplication
.context()
.getPackageManager()
.getPackageInfo(BaseApplication.context().getPackageName(),
0).versionCode;
} catch (PackageManager.NameNotFoundException ex) {
versionCode = 0;
}
return versionCode;
}

删除图像缓存:

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();
}
}
});
}

getSaveFolder方法:

/**
* 获取文件夹对象
*
* @return 返回SD卡下的指定文件夹对象,若文件夹不存在则创建
*/
public static File getSaveFolder(String folderName) {
File file = new File(getSDCardPath() + File.separator + folderName
+ File.separator);
file.mkdirs();
return file;
}

AppStart中开启了一个服务LogUploadService用来上传应用程序的日志。

在服务LogUploadService被开启后,根据情况进行如下几种操作:

  1. 读取osc本地文件夹下的日志信息

  2. 如果日志信息为空,服务停止—— LogUploadService.this.stopSelf()
  3. 如果日志信息不位空,上传日志;

当某一个组件比如Activity,通过调用startService()方法来开启一个服务时,系统会调用onStartCommand()方法。一旦这个方法执行之后,服务就会被开启并在后台独立的运行。如果你实现了这个方法,你必须在任务完成后通过调用stopSelf()或者stopService()来停止该服务。(如果你仅仅只想提供绑定,你不需要实现这个方法)。

日志上传的操作,封装在了OSChinaApi中,并且通过report来区分是bug还是反馈意见。

/**
* BUG上报
*
* @param data
* @param handler
*/
public static void uploadLog(String data, AsyncHttpResponseHandler handler) {
uploadLog(data, "1", handler);
}
/**
* 反馈意见
*
* @param data
* @param handler
*/
public static void feedback(String data, AsyncHttpResponseHandler handler) {
uploadLog(data, "2", handler);
}
 
uploadLog方法:
private static void uploadLog(String data, String report,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("app", "1");
params.put("report", report);
params.put("msg", data);
ApiHttpClient.post("action/api/user_report_to_admin", params, handler);
}
ApiHttpClient的post方法:
public static void post(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.post(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("POST ").append(partUrl).append("&")
.append(params).toString());
}

getAbsoluteapiUrl方法:

public static String getAbsoluteApiUrl(String partUrl) {
String url = partUrl;
if (!partUrl.startsWith("http:") && !partUrl.startsWith("https:")) {
url = String.format(API_URL, partUrl);
}
Log.d("BASE_CLIENT", "request:" + url);
return url;
}
 
API_URL的值:
private static String API_URL = "http://www.oschina.net/%s";

[Android]开源中国源码分析之一---启动界面的更多相关文章

  1. [Android]开源中国源码分析之二---DrawerLayout

    从启动界面到主界面之后的效果如图所示,采用的是v4包下的DrawerLayout, activity_main.xml文件如下: <!-- A DrawerLayout is intended ...

  2. Android开源框架源码分析:Okhttp

    一 请求与响应流程 1.1 请求的封装 1.2 请求的发送 1.3 请求的调度 二 拦截器 2.1 RetryAndFollowUpInterceptor 2.2 BridgeInterceptor ...

  3. Android开发Settings源码分析之主界面加载(二)

    现在都说互联网寒冬,其实只要自身技术能力够强,咱们就不怕!我这边专门针对Android开发工程师整理了一套[Android进阶学习视频].[全套Android面试秘籍].[Android知识点PDF] ...

  4. Appium Android Bootstrap源码分析之启动运行

    通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...

  5. Android 开源项目源码解析(第二期)

    Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...

  6. v87.01 鸿蒙内核源码分析 (内核启动篇) | 从汇编到 main () | 百篇博客分析 OpenHarmony 源码

    本篇关键词:内核重定位.MMU.SVC栈.热启动.内核映射表 内核汇编相关篇为: v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的 v75.03 鸿蒙内核源码分析(汇编基础) | ...

  7. Appium Server 源码分析之启动运行Express http服务器

    通过上一个系列Appium Android Bootstrap源码分析我们了解到了appium在安卓目标机器上是如何通过bootstrap这个服务来接收appium从pc端发送过来的命令,并最终使用u ...

  8. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  9. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

随机推荐

  1. poj 2226(最小覆盖)

    题目链接:http://poj.org/problem?id=2226 思路:将连续的横向水洼看成X集合中的一个点,连续的纵向水洼看成Y集合中的一个点,而将每个水点看成一条边,它连接了所在的X集合中的 ...

  2. Achartengine.jar绘制动态图形-饼图

    Achartengine.jar绘制动态图形一 --饼图 PS:我们在做安卓程序的时候,免不了会做一些图形,自己可以选择自定义view ,就是用Canvas画,也可以用写好的jar包,就是achart ...

  3. vip视频网站爬虫

    vip视频网站爬虫 电影网站:http://www.08ge.com/play/?make=dianying&id=fqvlYhH5QHb3Sh.html 找到<iframe>的i ...

  4. 【转】C#操作Word的超详细总结

    本文中用C#来操作Word,包括: 创建Word: 插入文字,选择文字,编辑文字的字号.粗细.颜色.下划线等: 设置段落的首行缩进.行距: 设置页面页边距和纸张大小: 设置页眉.页码: 插入图片,设置 ...

  5. 基于jquery 移动插件的实现

    引用谢灿勇 地址  http://www.cnblogs.com/st-leslie/p/6002148.html 一个思路分析:大致上实现的思路有以下两种. 一.判断块是否被按下(mousedown ...

  6. spring web中完成单元测试

    对于在springweb总完单元测试,之前找过些资料,摸索了很久,记录下最终自己使用的方法 1,创建测试类,创建测试资源文件夹 src/test/resources/WEB_INFO/conf 将工程 ...

  7. JavaWeb 之邮件发送

    1. 邮件协议概述 SMTP(Simple Mail Transfer Protocol, 简单邮件传输协议) 发邮件协议; POP3(Post Office Protocol Version 3, ...

  8. JDBC 入门

    1. JDBC 简介 JDBC (Java DataBase Connectivity) 就是 Java 数据库连接, 说白了就是用 Java 语言向 数据库发送 SQL 语句. JDBC 其实是访问 ...

  9. Qt 如何像 VS 一样创建项目模版?

    qt 存储模版路径位置:Qt\Qt5.9.5\Tools\QtCreator\share\qtcreator\templates\wizards 在里面随意复制一个模版,修改三项即可在 qt 中显示该 ...

  10. Java性能监控之javassist探索

    https://www.cnblogs.com/orionhp/p/6362615.html ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实 ...