开源中国android端版本号:2.4
在AndroidManifest.xml中找到程序的入口,
<activityandroid: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的值的关系。
@Overrideprotected 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() {
@Overridepublic 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
被开启后,根据情况进行如下几种操作:
- 读取osc本地文件夹下的日志信息
- 如果日志信息为空,服务停止——
LogUploadService.this.stopSelf()
- 如果日志信息不位空,上传日志;
当某一个组件比如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";
原文:http://www.cnblogs.com/xiaomoxian/p/5221483.html