[Android]開源中國源碼分析之一---啟動界面

来源:http://www.cnblogs.com/xiaomoxian/archive/2016/02/26/5221483.html
-Advertisement-
Play Games

開源中國android端版本號:2.4 啟動界面: 在AndroidManifest.xml中找到程式的入口, 屏幕方向設置為豎屏,主題為AppStartLoad,關於它的定義如下: welcome.png就是啟動頁顯示的圖片,填充了整個屏幕。 AppS...


開源中國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
     */
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一步、首先在你項目中創建一個包存放支持下拉刷新和上拉載入的類: 第二步、需要把兩個動畫導入進來,實現180度旋轉與360度旋轉: 第三步、需要把支持的下拉與上拉顯示的隱藏載入佈局給導入進來 第四步、需要添加strings.xml與colors.xml文件的內容添加到項目裡面: strings.xm
  • 分類:C#、Android、VS2015; 創建日期:2016-02-27 一、簡介 這一節演示如何利用以非同步方式(async、await)訪問SQLite資料庫。 二、示例4運行截圖 下麵左圖為初始頁面,右圖為單擊【創建資料庫】按鈕後的結果。 下麵左圖為單擊【添加單行】按鈕的結果,右圖為單擊【添加...
  • 近期因為項目的需要,研究了一下Android文件下載進度顯示的功能實現,接下來就和大家一起分享學習一下,希望對廣大初學者有幫助。 先上效果圖: 上方的藍色進度條,會根據文件下載量的百分比進行載入,中部的文本控制項用來現在文件下載的百分比,最下方的ImageView用來展示下載好的文件,項目的目的就是動
  • 作者: "@gzdaijie" 本文為作者原創,轉載請註明出處:http://www.cnblogs.com/gzdaijie/p/5222191.html 1.寫在前面 Android提供了豐富的 函數,本文介紹最常用的8種對話框的使用方法,包括普通(包含提示消息和按鈕)、列表、單選、多選、等待、
  • 從啟動界面到主界面之後的效果如圖所示,採用的是v4包下的DrawerLayout, activity_main.xml文件如下: ...
  • ReactNative高級交流群 127482131 或訪問 http://blog.1ygowu.com ReactNative技術專題
  • 1、自定義ViewGroup 1 /** 2 * Created by Administrator on 2016/2/26. 3 * 4 * --------自動換行的ViewGroup----------- 5 */ 6 public class LineWrapLayout extends V
  • 單例模式 單例模式幾乎是設計模式中最簡單的形式了。在使用單例時,單例對象的類必須保證只有一個勢力存在。許多時候整個系統只需要擁有一個全局對象。保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。經常用於設計約束或者為了控制對有限資源的訪問。 單例模式的實現思路:一個類只能創建一個實例(永遠是同一個
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...