zoukankan      html  css  js  c++  java
  • [Android]开源中国源码分析之一---启动界面

    开源中国android端版本号:2.4

    启动界面:

    Screenshot_20160226-171547

    在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";
  • 相关阅读:
    26种激发人创造力的天使商标设计
    TopFreeTheme精选免费模板【20130703】
    解决插入到MySql数据库中乱码问题
    商务名片创意搜罗
    10个优质PSD文件资源下载
    TopFreeTheme精选免费模板【20130701.特别版】
    【原创】关于java对象需要重写equals方法,hashcode方法,toString方法 ,compareto()方法的说明
    谨慎使用keySet:对于HashMap的2种遍历方式比较
    有关google的guava工具包详细说明
    java消除 list重复值及交集,并集,差集
  • 原文地址:https://www.cnblogs.com/xiaomoxian/p/5221483.html
Copyright © 2011-2022 走看看