﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>学习日记 &#187; C++</title>
	<atom:link href="https://www.softwareace.cn/?cat=12&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://www.softwareace.cn</link>
	<description>时刻想着为自己的产品多做一些对他好的事情</description>
	<lastBuildDate>Fri, 20 Mar 2026 06:58:28 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>ws2def.h(206) : error C2011: “sockaddr”: “struct”类型重定义</title>
		<link>https://www.softwareace.cn/?p=1700</link>
		<comments>https://www.softwareace.cn/?p=1700#comments</comments>
		<pubDate>Fri, 13 Oct 2017 07:40:11 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[win32]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1700</guid>
		<description><![CDATA[参考来源： http://www.cnblogs.com/tonyyang132/archive/2009/1 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><span style="color: #3d3d3d;"><b>参考来源：</b></p>
<p>http://www.cnblogs.com/tonyyang132/archive/2009/10/14/1583110.html</p>
<p>https://social.msdn.microsoft.com/Forums/vstudio/en-US/671124df-c42b-48b8-a4ac-3413230bc43b/dll-compilationredefinition-error?forum=vclanguage</span><b style="color: #3d3d3d;"><br />
现象：</b><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">使用winsock2后，出现许多重定义错误。</span><br style="color: #3d3d3d;" /><b style="color: #3d3d3d;">原因是:</b><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">头文件包含顺序错误，这两个头文件是：#include &lt;winsock2.h&gt;和#include&lt;windows.h&gt;</span><br style="color: #3d3d3d;" /><b style="color: #3d3d3d;">解决办法：</b><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">在使用的地方加上如下语句：</span><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">//socket</span><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">#ifndef WIN32_LEAN_AND_MEAN</span><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">#define WIN32_LEAN_AND_MEAN</span><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">#endif</span><br style="color: #3d3d3d;" /><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">#include &lt;windows.h&gt;</span><br style="color: #3d3d3d;" /><span style="color: #3d3d3d;">#include &lt;winsock2.h&gt;</span></p>
<p>http://blog.163.com/lys_19850716/blog/static/84129044201611653736905/</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1700</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>让EXE导出函数</title>
		<link>https://www.softwareace.cn/?p=1687</link>
		<comments>https://www.softwareace.cn/?p=1687#comments</comments>
		<pubDate>Fri, 18 Aug 2017 01:09:57 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Windows api]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1687</guid>
		<description><![CDATA[[crayon-69ec6758959cb880027507/] http://bbs.pediy.com/t [&#8230;]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">初步搞定。

问题来源：
偶然发现OllyDBG.exe导出了一堆函数，这些函数都是供其插件调用的。对这种体系结构很感
兴趣，想弄清楚它的实现原理。后来又看到梁肇新的书《编程高手箴言》第278页提到的调用
门，觉得都应该差不多。

三种不同的解决办法（原理可能是一样的，:)）：

1）在导出函数声明之前加上__declspec(dllexport)。例：
__declspec(dllexport) int Add(int a, int b);
__declspec(dllexport) int Sub(int a, int b);
__declspec(dllexport) int Mul(int a, int b);
__declspec(dllexport) int Div(int a, int b);

2）在链接器参数中设置。例：
#pragma comment(linker, "/EXPORT:_Add,@1,NONAME")
#pragma comment(linker, "/EXPORT:_Sub,@2,NONAME")
#pragma comment(linker, "/EXPORT:_Mul,@3,NONAME")
#pragma comment(linker, "/EXPORT:_Div,@4,NONAME")

3）添加一个def文件，例：
EXPORTS
        Add       @1  NONAME
        Sub       @2  NONAME
        Mul       @3  NONAME
        Div       @4  NONAME
另需要在链接器命令行参数中指定def文件名：
/DEF:Callee.def
注意：在def文件中不要有
LIBRARY [library][BASE=address]
这样的语句。

相比较而言，后两种方法可以设置更多的参数。

函数举例：

extern "C" 
{

        int Add(int a, int b)
        {
                return (a + b);
        }

        int Sub(int a, int b)
        {
                return (a - b);
        }

        int Mul(int a, int b)
        {
                return (a * b);
        }

        int Div(int a, int b)
        {
                if (b == 0)
                        return 0;
                else
                        return (a / b);
        }

}

编译时会自动生成相应的导出库（lib）文件，供调用者使用。

调用方法和普通的动态链接库调用一样。
调用者必须能够找到被调用者的位置，否则报错，被调用者是否运行不影响。

调用代码举例：

extern "C"
{
        int Add(int a, int b);
        int Sub(int a, int b);
        int Mul(int a, int b);
        int Div(int a, int b);
}

#pragma comment (lib, "Callee.lib")

void CCallerDlg::OnBnClickedCalculate()
{
        // TODO: Add your control notification handler code here
        UpdateData(TRUE);

        switch (((CComboBox *)GetDlgItem(IDC_COMBO_OPERATOR))-&gt;GetCurSel())
        {
        case ADD:
                {
                        m_iResult = Add(m_iNum1, m_iNum2);
                        break;
                }
        case SUB:
                {
                        m_iResult = Sub(m_iNum1, m_iNum2);
                        break;
                }
        ...
        ...

我在OD中跟了一下，发现这跟调用动态链接库也差不多。
不过那几个函数被映射到下面的地址处：

003810F0 &gt;  8B4424 08                 mov     eax, dword ptr [esp+8]
003810F4    8B4C24 04                 mov     ecx, dword ptr [esp+4]
003810F8    03C1                      add     eax, ecx
003810FA    C3                        retn
003810FB    CC                        int3
003810FC    CC                        int3
003810FD    CC                        int3
003810FE    CC                        int3
003810FF    CC                        int3
00381100 &gt;  8B4424 04                 mov     eax, dword ptr [esp+4]
00381104    2B4424 08                 sub     eax, dword ptr [esp+8]
00381108    C3                        retn
00381109    CC                        int3
0038110A    CC                        int3
0038110B    CC                        int3
0038110C    CC                        int3
0038110D    CC                        int3
0038110E    CC                        int3
0038110F    CC                        int3
00381110 &gt;  8B4424 04                 mov     eax, dword ptr [esp+4]
00381114    0FAF4424 08               imul    eax, dword ptr [esp+8]
00381119    C3                        retn
0038111A    CC                        int3
0038111B    CC                        int3
0038111C    CC                        int3
0038111D    CC                        int3
0038111E    CC                        int3
0038111F    CC                        int3
00381120 &gt;  8B4C24 08                 mov     ecx, dword ptr [esp+8]
00381124    85C9                      test    ecx, ecx
00381126    75 03                     jnz     short 0038112B
00381128    33C0                      xor     eax, eax
0038112A    C3                        retn

跟常规的动态链接库被映射到高地址处略有不同。
还不知道是什么原因。

结论：
EXE完全可以和DLL一样导出函数，一样被调用。

进一步的工作：
我发现这个例子跟OllyDbg.exe还是有些不同，跟“调用门”的说法也有不同。这里实际上还是
跟DLL差不多的原理。下一步争取实现一个跟OllyDbg.exe差不多的例子。</pre><p></p>
<p>http://bbs.pediy.com/thread-56840.htm</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1687</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>win7下默认显示托盘图标的</title>
		<link>https://www.softwareace.cn/?p=1684</link>
		<comments>https://www.softwareace.cn/?p=1684#comments</comments>
		<pubDate>Thu, 17 Aug 2017 08:55:32 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[Windows api]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1684</guid>
		<description><![CDATA[[crayon-69ec6758963c8536989795/] 之前之后 http://bbs.pediy. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">#include "stdafx.h"
 
#include &lt;conio.h&gt;
#include &lt;windows.h&gt;
#include &lt;Shlwapi.h&gt;
 
#pragma comment(lib, "shlwapi.lib")
 
typedef struct tagNOTIFYITEM
{
    PWSTR pszExeName;
    PWSTR pszTip;
    HICON hIcon;
    HWND hWnd;
    DWORD dwPreference;
    UINT uID;
    GUID guidItem;
} NOTIFYITEM, *PNOTIFYITEM;
 
class __declspec(uuid("D782CCBA-AFB0-43F1-94DB-FDA3779EACCB")) INotificationCB : public IUnknown
{
    virtual HRESULT __stdcall Notify (ULONG, NOTIFYITEM *) = 0;
};
 
class __declspec(uuid("FB852B2C-6BAD-4605-9551-F15F87830935")) ITrayNotify : public IUnknown
{
public:
    virtual HRESULT __stdcall RegisterCallback(INotificationCB* callback) = 0;
    virtual HRESULT __stdcall SetPreference(const NOTIFYITEM* notify_item) = 0;
    virtual HRESULT __stdcall EnableAutoTray(BOOL enabled) = 0;
};
 
class __declspec(uuid("D133CE13-3537-48BA-93A7-AFCD5D2053B4")) ITrayNotifyWindows8 : public IUnknown
{
public:
    virtual HRESULT __stdcall RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
    virtual HRESULT __stdcall UnregisterCallback(unsigned long*) = 0;
    virtual HRESULT __stdcall SetPreference(NOTIFYITEM const*) = 0;
    virtual HRESULT __stdcall EnableAutoTray(BOOL) = 0;
    virtual HRESULT __stdcall DoAction(BOOL) = 0;
};
 
const CLSID CLSID_TrayNotify = {0x25DEAD04, 0x1EAC, 0x4911, {0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};
 
class NotificationMgr : public INotificationCB
{
public:
    NotificationMgr(){
        m_pTrayNotify = NULL;
    }
 
    HRESULT __stdcall QueryInterface (
        REFIID riid,
        PVOID *ppv)
    {
        if (ppv == NULL)
            return E_POINTER;
 
        if (riid == __uuidof (INotificationCB)) {
            *ppv = (INotificationCB *) this;
        }else if (riid == IID_IUnknown) {
            *ppv = (IUnknown *) this;
        }else{
            return E_NOINTERFACE;
        }
 
        ((IUnknown *) *ppv) -&gt; AddRef ();
 
        return S_OK;
    }
 
    ULONG __stdcall AddRef (VOID)
    {
        return 1;
    }
 
    ULONG __stdcall Release (VOID)
    {
        return 1;
    }
    HRESULT __stdcall Notify (ULONG Event, NOTIFYITEM * NotifyItem){
        printf("event:%d Preference:%d id:%d path:%ls\n", Event, NotifyItem-&gt;dwPreference, NotifyItem-&gt;uID, NotifyItem-&gt;pszExeName);
        if (StrStrIW(NotifyItem-&gt;pszExeName, L"qq.exe")){
            if (m_pTrayNotify){
                NotifyItem-&gt;dwPreference = 2;
                m_pTrayNotify-&gt;SetPreference(NotifyItem);
            }
        }
        return S_OK;
    }
 
public:
    ITrayNotify * m_pTrayNotify;
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    ITrayNotify *pTrayNotify;
    NOTIFYITEM NotifyItem = {0};
    NotificationMgr NotiMgr;
 
    CoInitialize(NULL);
 
    //
    // for win7
    //
     
    HRESULT hr = CoCreateInstance (
       CLSID_TrayNotify,
       NULL,
       CLSCTX_LOCAL_SERVER,
       __uuidof(ITrayNotify),
       (PVOID *)&amp;pTrayNotify);
     
    if (!SUCCEEDED(hr)){
        printf("create instance of ITrayNotify error\n");
        return -1;
    }
     
    //
    // register callback
    //
     
    NotiMgr.m_pTrayNotify = pTrayNotify;
    hr = pTrayNotify-&gt;RegisterCallback(&amp;NotiMgr);
     
    printf("over\n");
 
    pTrayNotify-&gt;RegisterCallback(NULL);
    pTrayNotify-&gt;Release();
     
    _getch();
 
    return 0;
}</pre><p><span style="color: #0b151d;">之前</span><br style="color: #0b151d;" /><img style="color: #0b151d;" src="http://bbs.pediy.com/upload/attach/201507/240026_2ep5sqn0kpgycrc.png" alt="" width="468" height="436" /><br style="color: #0b151d;" /><br style="color: #0b151d;" /><span style="color: #0b151d;">之后</span><br style="color: #0b151d;" /><img style="color: #0b151d;" src="http://bbs.pediy.com/upload/attach/201507/240026_4lh79s9ykutn8oz.png" alt="" width="524" height="389" /></p>
<p>http://bbs.pediy.com/thread-202658.htm</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1684</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>沉浸式中显示 PopupWindow</title>
		<link>https://www.softwareace.cn/?p=1680</link>
		<comments>https://www.softwareace.cn/?p=1680#comments</comments>
		<pubDate>Tue, 08 Aug 2017 06:53:19 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1680</guid>
		<description><![CDATA[在全屏沉浸模式时（Immersive Full-Screen Mode），如果弹出 Dialog 或 Popu [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #7f8c8d;">在全屏沉浸模式时（Immersive Full-Screen Mode），如果弹出 Dialog 或 PopupWindow，则会自动退出沉浸模式。</p>
<p style="color: #7f8c8d;">退出沉浸式的原因是因为 Activity 的 Window 焦点被抢走了，Window 中的 DecorView 状态改变导致了退出。</p>
<p style="color: #7f8c8d;">如果要继续保持沉浸模式。对于 Dialog 情况，这里有<a style="color: #3498db;" href="http://stackoverflow.com/a/23207365">解决办法</a> 。 Dialog 在初始化时会生成新的 Window，先禁止 Dialog Window 获取焦点，等 Dialog 显示后对 Dialog Window 的 DecorView 设置 <code>setSystemUiVisibility</code> ，接着再获取焦点。 这样表面上看起来就没有退出沉浸模式。</p>
<p style="color: #7f8c8d;">而 PopupWindow 并没有创建新的 Window，只是将 PopupWindow 的 View 添加到当前的 WindowManager。不过可以对 PopupWindow 设置 <code>setFocusable</code>。</p>
<p style="color: #7f8c8d;">同理，先在失焦的状态，弹出 PopupWindow ， 再对 PopupWindow 的 DecorView 设置 <code>setSystemUiVisibility</code> ，最后获取焦点即可。 虽然 PopupWindow 对外没有暴露出 DecorView ，但只要是 PopupWindow 中的可见 View 都行。</p>
<p></p><pre class="crayon-plain-tag">public class MainActivity extends AppCompatActivity {

    private PopupWindow mPopupWindow;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int windowWidth = 480;
        int windowHeight = 120;

        TextView popupView = (TextView) LayoutInflater.from(getApplicationContext())
                .inflate(android.R.layout.simple_list_item_1, null);
        popupView.setText("PopupWindow");
        popupView.setGravity(Gravity.CENTER);
        popupView.setBackgroundColor(Color.BLACK);
        popupView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "PopupWindow Click", Toast.LENGTH_SHORT)
                        .show();
            }
        });

        mPopupWindow = new PopupWindow(popupView, windowWidth, windowHeight);
        mPopupWindow.setFocusable(false);
        mPopupWindow.setBackgroundDrawable(new ColorDrawable());
        mPopupWindow.setOutsideTouchable(true);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                if (!mPopupWindow.isShowing()) {
                    showPopup(v);
                } else {
                    mPopupWindow.dismiss();
                }
            }
        });
    }

    @Override public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus) {
            fullScreenImmersive(getWindow());
        }
    }

    public void showPopup(View anchor) {
        mPopupWindow.setFocusable(false);
        mPopupWindow.update();

        PopupWindowCompat.showAsDropDown(mPopupWindow, anchor,
                -mPopupWindow.getWidth() / 2 + anchor.getWidth() / 2,
                -mPopupWindow.getHeight() - anchor.getHeight(), Gravity.CENTER);

        fullScreenImmersive(mPopupWindow.getContentView());
        mPopupWindow.setFocusable(true);
        mPopupWindow.update();
    }

    public void fullScreenImmersive(Window window) {
        if (window != null) {
            fullScreenImmersive(window.getDecorView());
        }
    }

    public void fullScreenImmersive(View view) {
        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {
            int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
            view.setSystemUiVisibility(uiOptions);
        }
    }
}</pre><p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1680</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个强悍的android版本检测更新库</title>
		<link>https://www.softwareace.cn/?p=1677</link>
		<comments>https://www.softwareace.cn/?p=1677#comments</comments>
		<pubDate>Thu, 27 Jul 2017 04:14:31 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1677</guid>
		<description><![CDATA[CheckVersionLib 现在热更新技术挺火的，大公司都出了自己的热更新框架，但是各家热更新都有各自优缺 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>
<h1>CheckVersionLib</h1>
<p>现在热更新技术挺火的，大公司都出了自己的热更新框架，但是各家热更新都有各自优缺点，终究不能解决所有bug，万不得已还是得进行版本升级，这是一个android上的自动版本检测并更新库。库集成了检测版本、下载版本以及自动安装升级</p>
<h2>特点</h2>
<ul>
<li>任何地方都可以检测</li>
<li>任何地方都可以弹出升级对话框</li>
<li>自定义性强，手动回调解析，适用于各种版本检测接口</li>
<li>自动处理下载和升级</li>
<li>自定义界面</li>
<li>支持强制更新</li>
</ul>
<h2>效果</h2>
<div class="image-package"><img src="//upload-images.jianshu.io/upload_images/1982650-a6775406529f9fc1.gif?imageMogr2/auto-orient/strip" alt="" data-original-src="http://upload-images.jianshu.io/upload_images/1982650-a6775406529f9fc1.gif?imageMogr2/auto-orient/strip" /></p>
<div class="image-caption">custom.gif</div>
</div>
<div class="image-package"><img src="//upload-images.jianshu.io/upload_images/1982650-7349fda4332cc577.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300" alt="" data-original-src="http://upload-images.jianshu.io/upload_images/1982650-7349fda4332cc577.png?imageMogr2/auto-orient/strip%7CimageView2/2" /></p>
<div class="image-caption">style1.png</div>
</div>
<div class="image-package"><img src="//upload-images.jianshu.io/upload_images/1982650-906542f3c3aac27b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300" alt="" data-original-src="http://upload-images.jianshu.io/upload_images/1982650-906542f3c3aac27b.png?imageMogr2/auto-orient/strip%7CimageView2/2" /></p>
<div class="image-caption">style2.png</div>
</div>
<h2>使用步骤</h2>
<h3>android studio导入</h3>
<p><code>compile 'com.allenliu.versionchecklib:library:1.0.6'</code></p>
<h3>如何使用</h3>
<p>1.自定义service，service继承 <code>AVersionService</code>，实现其中的 <code>onResponses(AVersionService service, String response)</code>抽象方法.</p>
<p>该方法主要是请求版本接口的回调，由于不同的使用者版本检测接口返回数据类型不一致，所以你需要自定解析数据，然后判断版本号之后调用升级对话框，如果使用库自带的直接调用如下方法: <code>service.showVersionDialog(downloadUrl,title,updateMsg )</code><br />
示例代码:</p><pre class="crayon-plain-tag">&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (serverVersion &amp;gt; clientVersion) { 
      &lt;span class=&quot;hljs-comment&quot;&gt;//传入下载地址，以及版本更新消息&lt;/span&gt;
     service.showVersionDialog(downloadUrl,&lt;span class=&quot;hljs-built_in&quot;&gt;title&lt;/span&gt;,updateMsg );}</pre><p>如果拿到数据之后，不使用库的方法，那么你可以在回调 里做自己想做的事。记得这里需要自己手动关闭<code>service</code>（如果调用showVersionDialog则不需要手动关闭）</p>
<p>2.在任意地方开启自定义service，并传入<code>VersionParam</code></p><pre class="crayon-plain-tag">versionParams = new VersionParams().setRequestUrl(&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.baidu.com&quot;&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;Intent&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;intent&lt;/span&gt; = new &lt;span class=&quot;hljs-keyword&quot;&gt;Intent&lt;/span&gt;(this, DemoService.&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;intent&lt;/span&gt;.putExtra(AVersionService.VERSION_PARAMS_KEY, versionParams);
    startService(&lt;span class=&quot;hljs-keyword&quot;&gt;intent&lt;/span&gt;);</pre><p><code>VersionParams</code>有如下方法，除了requestUrl都是可选值</p>
<div class="image-package"><img src="//upload-images.jianshu.io/upload_images/1982650-e8d0174f4867c86c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" data-original-src="http://upload-images.jianshu.io/upload_images/1982650-e8d0174f4867c86c.png?imageMogr2/auto-orient/strip%7CimageView2/2" /></p>
<div class="image-caption">versionparams.png</div>
</div>
<h3><strong>自定义界面</strong></h3>
<p>如果想自定义界面，只需创建一个继承自<code>VersionDialogActivity</code>的Activity,Activity设置Theme为透明：</p>
<p><code>android:theme="@style/versionCheckLibvtransparentTheme"</code></p>
<p>开启Service的时候，将自定义的Activity传入VersionParams</p>
<p><code>setCustomDownloadActivityClass(CustomVersionDialogActivity.class)</code></p>
<ul>
<li>自定义 版本dialog,重写 <code>showVersionDialog()</code> ,在里面实现自己的逻辑，最后调用<code>downloadFile(url)</code>或者<code>downloadFile(url,filecallback)</code>注意不要调用父类的方法</li>
<li>自定义 下载中dialog，重写<code>showLoadingDialog(int currentProgress)</code>,在里面实现自己的逻辑</li>
<li>自定义 下载失败dialog ,重写<code>showFailDialog</code>，实现自己的逻辑</li>
<li>强制更新。如果使用默认的版本dialog，<code>setCancelClickListner</code>回调里实现，具体用法请看demo</li>
<li>自定义 版本dialog,重写 <code>showVersionDialog()</code> ,在里面实现自己的逻辑，最后调用<code>downloadFile(url)</code>或者<code>downloadFile(url,filecallback)</code>注意不要调用父类的方法</li>
<li>除此之外还可以在定义的Activity里面监听一些下载和点击回调</li>
<li>自定义 版本dialog,重写 <code>showVersionDialog()</code> ,在里面实现自己的逻辑，最后调用<code>downloadFile(url)</code>或者<code>downloadFile(url,filecallback)</code>注意不要调用父类的方法<br />
<pre class="crayon-plain-tag">setOnDownloadSuccessListener(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);

setCommitClickListener(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);

setCancelClickListener(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);

setOnDownloadingListener(&lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;);</pre>
</li>
</ul>
<h3>下载通知栏图标和文字替换</h3>
<p>需要自定义图标只需在mimap文件下建立<code>ic_launcher</code>图标，替换标题只需在项目xml定义<code>app_name</code>属性,还有其他一些属性替换，如下表:</p>
<table>
<thead>
<tr>
<th>属性名</th>
<th>属性值</th>
</tr>
</thead>
<tbody>
<tr>
<td>versionchecklib_confirm</td>
<td>确认</td>
</tr>
<tr>
<td>versionchecklib_cancel</td>
<td>取消</td>
</tr>
<tr>
<td>versionchecklib_retry</td>
<td>重试</td>
</tr>
<tr>
<td>versionchecklib_download_fail_retry</td>
<td>下载失败是否重试？</td>
</tr>
<tr>
<td>versionchecklib_download_finish</td>
<td>下载完成，点击安装</td>
</tr>
<tr>
<td>versionchecklib_downloading</td>
<td>正在下载中&#8230;</td>
</tr>
<tr>
<td>versionchecklib_check_new_version</td>
<td>检测到新版本</td>
</tr>
<tr>
<td>versionchecklib_download_fail</td>
<td>下载失败，点击重试</td>
</tr>
</tbody>
</table>
<p>更详细的使用请看demo<br />
<code>欢迎star和提issue</code><br />
<a href="https://github.com/AlexLiuSheng/CheckVersionLib" target="_blank">传送门</a></p>
</div>
<p>链接：http://www.jianshu.com/p/e246dd3b9c8a</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1677</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>错误：INSTALL_FAILED_VERSION_DOWNGRADE</title>
		<link>https://www.softwareace.cn/?p=1667</link>
		<comments>https://www.softwareace.cn/?p=1667#comments</comments>
		<pubDate>Tue, 18 Jul 2017 02:21:57 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1667</guid>
		<description><![CDATA[安卓新版本的 ADT 在安装apk的时候，会检查当前要运行的版本 AndroidManifest.xml 中的 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #555555;">安卓新版本的 ADT 在安装apk的时候，会检查当前要运行的版本 AndroidManifest.xml 中的 versionCode 和手机中已经安装过的该程序的 versionCode 做对比，如果手机中的 versionCode 比较高，ADT 就会提示出错：INSTALL_FAILED_VERSION_DOWNGRADE</p>
<p style="color: #555555;">所以，解决这个问题就是修改 AndroidManifest.xml 中的 versionCode 修改大一些就可以了。</p>
<p style="color: #555555;">要么就是把手机中已经安装的包卸载掉。</p>
<p style="color: #555555;">这里只是为了说明错误原因。</p>
<p style="color: #555555;">http://blog.csdn.net/catoop/article/details/48086429</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1667</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android Hugo</title>
		<link>https://www.softwareace.cn/?p=1663</link>
		<comments>https://www.softwareace.cn/?p=1663#comments</comments>
		<pubDate>Mon, 10 Jul 2017 02:07:22 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1663</guid>
		<description><![CDATA[https://github.com/JakeWharton/hugo JakeWharton 大神的日志框架 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #3f3f3f;"><a style="color: #0c89cf;" href="https://github.com/JakeWharton/hugo" target="_blank">https://github.com/JakeWharton/hugo</a></p>
<p style="color: #3f3f3f;">JakeWharton 大神的日志框架，用于 debug build 时显示方法的参数、返回值、运行时间。</p>
<h2 id="用法" style="font-weight: 100; color: #3f3f3f;">用法</h2>
<p style="color: #3f3f3f;">将 <code>@DebugLog</code> 注解添加到方法前即可。</p>
<p></p><pre class="crayon-plain-tag">@DebugLog
public String getName(String first, String last) {
  SystemClock.sleep(15); // Don't ever really do this!
  return first + " " + last;
}

V/Example: ⇢ getName(first="Jake", last="Wharton")
V/Example: ⇠ getName [16ms] = "Jake Wharton"</pre><p>&nbsp;</p>
<p style="color: #3f3f3f;">打印日志只会在 debug builds 发生，注解也不会在任何编译后的 class 文件出现。完全不影响非 debug builds.</p>
<h2 id="配置" style="font-weight: 100; color: #3f3f3f;">配置</h2>
<p style="color: #3f3f3f;"><a style="color: #0c89cf;" href="https://github.com/JakeWharton/hugo/blob/master/hugo-example/build.gradle" target="_blank">Example</a></p>
<p></p><pre class="crayon-plain-tag">buildscript {
  repositories {
    mavenCentral()
  }

  dependencies {
    classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
  }
}

apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.hugo'</pre><p><span style="color: #3f3f3f;">可以临时性禁用:</span></p><pre class="crayon-plain-tag">hugo {
  enabled false
}</pre><p>&nbsp;</p>
<p style="color: #3f3f3f;">也支持在运行时切换, use <code>Hugo.setEnabled(true|false)</code></p>
<h2 id="问题" style="font-weight: 100; color: #3f3f3f;">问题</h2>
<p style="color: #3f3f3f;">运行时 <a class="replace_word" style="font-weight: bold; color: #df3434;" title="Java 知识库" href="http://lib.csdn.net/base/java" target="_blank">Java</a>.lang.VerifyError 未找到解决方案，也好久没发新版本了，回头再看看吧。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1663</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>5分钟教你打造一个秒开的Android App</title>
		<link>https://www.softwareace.cn/?p=1661</link>
		<comments>https://www.softwareace.cn/?p=1661#comments</comments>
		<pubDate>Mon, 10 Jul 2017 01:53:52 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1661</guid>
		<description><![CDATA[背景： 近日在开发过程中，发现每次点击app从桌面启动都有一个在桌面明显的等待时间，机型越低端的越明显，冷启动 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #222222;"><span style="font-weight: bold;">背景：</span></p>
<p style="color: #222222;">近日在开发过程中，发现每次点击app从桌面启动都有一个在桌面明显的等待时间，机型越低端的越明显，冷启动优化看来已经势在必行，所以怒而一顿研究再解决之。话不多说先上优化前后效果图：</p>
<p style="color: #222222;">买家秀：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c48000243b7f1409744" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">淘宝秀：</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c3b00025120a6ab050e" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;"><span style="font-weight: bold;">Android App启动流程：</span></p>
<p style="color: #222222;">俗话说要想优化好，流程不可少！关于android app启动的流程图如下：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c3900024534d5439501" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">总结一下一个完成的冷启动app过程应该是经过：</p>
<p style="color: #222222;">Zygote Fork Proccess -&gt; Application:attachBaseContext() -&gt; Application:onCreate() -&gt; MainActiviity:onCreate()</p>
<p style="color: #222222;">这里主要是把相应的生命周期回调写出来。 因为一般大家的业务代码都是在这些函数回调中调用。</p>
<p style="color: #222222;"><span style="font-weight: bold;">App冷启动相关优化点</span></p>
<p style="color: #222222;">1. 生命周期内减少耗时操作：</p>
<p style="color: #222222;">· Application:attachBaseContext()：</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c43000294a4c19aefde" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">这个方法中一般雷区主要都在这句代码上，因为在Android 5.0（API 21) 以下会存在65535方法数分包的问题，当dex过大时会导致Application启动慢， ANR或者ClassNotFound等异常，关于分包解决和优化方案网上一堆就不在做赘述了。</p>
<p style="color: #222222;">· Application:onCreate()</p>
<p style="color: #222222;">这个方法是需要重点优化的，因为大家的第三方插件初始化一般都会放在这里，在Application初始化做繁重的东西会严重阻塞app启动（DiskIO，网络请求等）。以下是我们第三方插件初始化的耗时：</p>
<p style="color: #222222;">debug：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c41000243aa96905c44" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">release：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c43000294a5e7b766e5" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">这里把debug和release下的时间都贴出来，是希望大家不要重蹈覆辙。。。 因为debug模式下和release模式下一个是1000ms左右， 一个是300ms左右，误差很大，请大家一定要在release下测试数据！！！！</p>
<p style="color: #222222;">针对于解决第三方插件初始化耗时方案一般是：</p>
<p style="color: #222222;">1.SDK分优先级加载，非必要SDK由懒加载实现。</p>
<p style="color: #222222;">2.可以多线程初始化的sdk由多线程方式来进行初始化。</p>
<p style="color: #222222;">· MainActiviity:onCreate()</p>
<p style="color: #222222;">同上一样，尽量不要在此布局做一些耗时的操作或者呈现一些过于复杂的布局。在具体分析自己的app时发现onCreate中有这样一行代码：</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c3b0002511c0e4a2e4c" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">其作用是希望用户在打开时，一定能看见Splash的画面，主动延迟了1s加载。这里其实有更好的解决办法处理，则是把跳转MainPage的方法放在onResume中而不是放在onCreate中。因为Android系统中onResume一定是处于可见可交互的状态，用户一定能看见SplashActivity再去跳转，由系统生命周期决定，而不是固定的等待1s，此处优化后启动速度又提升了500ms。所以建议大家以后还是遵循生命周期去做一些事情，尽量别进行人为延迟阻塞。</p>
<p style="color: #222222;">2. 避免冷启动</p>
<p style="color: #222222;">App启动方式一般有3种：</p>
<p style="color: #222222;">· ColdStart ——冷启动：</p>
<p style="color: #222222;">此种方式最为耗时，一般是因为进程被干掉，系统需要重新fork进程进行一系列初始化。</p>
<p style="color: #222222;">· WarmStart ——暖启动</p>
<p style="color: #222222;">比ColdStart稍快，因为app的所有Activities还常驻在内存中，并没有被杀掉，所做的只是把app从后台提到前台来展示，并不需要重走初始化一系列行为，减少了对象初始化、布局加载等工作。但其行为表现与冷启动一致，是会displays a blank screen直到App渲染activity。这个blank screen后面会解释。</p>
<p style="color: #222222;">· LukeWarm Start——热启动</p>
<p style="color: #222222;">启动方式最快，类似于返回键退出应用又立即进入的那种行为。</p>
<p style="color: #222222;">优化方案：</p>
<p style="color: #222222;">既然冷启动那么慢，我们就在非用户主动kill进程或系统通知kill进程的其他情况下不再主动退出进程。那答案很简单了，就是在位于Activity栈底activity中Hook其返回键行为，保证用户点击返回键后不再退出app。在我们App里位于我们栈底的一定是我们的MainActivity，因为一系统行为都是由其向下衍生的。所以只需加入以下几句话：</p>
<p style="color: #222222;"><img src="http://p9.pstatp.com/large/2c48000243b6f21e623a" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">moveTaskToBack：作用是不再Finish到此Activity，仅仅是把它放到后台隐藏。类似于用户主动触发系统Home键的效果。在同是点击返回键优化前后的对比如下：</p>
<p style="color: #222222;">优化前：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c48000243b832a137ee" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">优化后：</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c3900024538a720bf21" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">若图1中时间久后进程回收后优化效果会更为明显。</p>
<p style="color: #222222;">3.WindowBackGround——脱下秒开的最后一层薄丝袜</p>
<p style="color: #222222;">经过上面一顿操作后，我发现然并卵！！！启动速度是提升了，但是App一点击还是会在桌面停顿一下。哇呀~很难受~细细思考了一下，一个APP启动无论如何都是会新Fork进程，难道就是这个问题导致其在桌面上停顿一会儿？那其他app又是怎么做到秒开的呢？在AndroidDeveloper的Launch-Time Performance有这么一句话：</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c3b0002511ec363ec14" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">其实在创建App进程时，android系统会为你立即显示一个background window，然后再去创建app进程，当app完成first draw时，会立即由你的MainActivity（即默认启动的Activity）替换掉它。这里的background window就是上文WarmStart中提到的blank screen。谜底到此解开所谓的秒开原来就是视觉欺骗。。。所以说有人给你说他只是仅仅是优化生命周期内初始化代码达到秒开都是扯淡。但不得不承认这样用户体验大大的提升了，一点击launcher就渲染好一个背景图片，给用户一种已经启动的感觉，前面做的一系列优化，不过为了让用户少看一会儿系统给渲染的black window。</p>
<p style="color: #222222;">那为什么我们的APP会出现在系统桌面上停留一会，而不是渲染背景图呢？原来在项目创建时，系统会为launcherActivity默认了一个LightTheme，这样就会导致App点击启动后会白屏一段时间然后展示自己的Activity，为了解决白屏的问题把theme主题换成透明的就像下面</p>
<p style="color: #222222;"><img src="http://p9.pstatp.com/large/2c3900024535e433e675" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">但其实这样虽然解决了白屏的问题，但是就会出现上文所说的，点击后停留在桌面一会儿，直至MainActivity渲染出来。这是大部分App的做法，但并不是最佳解决方案。</p>
<p style="color: #222222;">WindowBackground最佳解决方案：</p>
<p style="color: #222222;">应该由windowBackground此属性作为你的品牌推广页或者logo页，如果你的SplashActivity完全不需要做任何初始化，只是希望有个闪屏页，完全可以由windowBackground来满足。</p>
<p style="color: #222222;">1.设置自定义带windowBackground的Theme</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c3b0002511f6535e187" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">前两行代码是设置Theme不透明并且默认渲染的背景图是我们必看影视闪屏页的图片。</p>
<p style="color: #222222;">- windowBackground：关键，主要设置你想要的背景图或者是动态自绘的drawable皆行，这个视图会在你冷启动时渲染给用户过渡看。</p>
<p style="color: #222222;">- windowFullscreen：全屏展示，免得顶部状态栏显现颜色不一致过于脱节和突兀</p>
<p style="color: #222222;">2. 为你的launcher Activity设置你的启动Theme</p>
<p style="color: #222222;"><img src="http://p1.pstatp.com/large/2c43000294a627f17017" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">3. 在Launch Activity启动后再把主题设置回自己的AppTheme</p>
<p style="color: #222222;"><img src="http://p9.pstatp.com/large/2c41000243acb68c253b" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">此时你的App就能完成秒开了！</p>
<p style="color: #222222;"><span style="font-weight: bold;">推荐测试工具</span></p>
<p style="color: #222222;">最终我们App从launcher点击到第一个Activity渲染完成总共需要时间是888ms，很吉利！</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c43000294a8e57390cc" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">· Time to full Display</p>
<p style="color: #222222;">上图的那行日志是由系统打印出来的，意思就是渲染Acitivity所需要的时间，如果是第一个Activity启动时长也是算在内的。 在Android4.4（API19）以上才会有此Log打出，在verbose级别搜索Displayed即可。不仅可以看自己的还可以看到其他APP的启动时长。</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c3900024537a483743d" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">附带一张小米4上业界各大App的冷启动时长~仅供参考~</p>
<p style="color: #222222;">· Hugo</p>
<p style="color: #222222;">执行时间打印神器，集成至项目后，只需在想要测试的地方加上注解即可：</p>
<p style="color: #222222;"><img src="http://p9.pstatp.com/large/2c390002453918f52c9b" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">可以是class级别，也可以是函数级别。如果注解是Appication类级别，还会把各大生命周期回调函数执行时间打印出来及其方便！GitHub传送门</p>
<p style="color: #222222;">效果如下：</p>
<p style="color: #222222;"><img src="http://p3.pstatp.com/large/2c41000243ad4f0a49fe" alt="5分钟教你打造一个秒开的Android App" /></p>
<p style="color: #222222;">· Stetho</p>
<p style="color: #222222;">这是非死不可出的调试神器，如果开发android这个没用过的话，你一定会觉得相见恨晚！</p>
<p style="color: #222222;">原文链接：http://www.gad.qq.com/article/detail/28915?ADTAG=gad.tg.tt</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1661</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>android 自定义 actionBar</title>
		<link>https://www.softwareace.cn/?p=1658</link>
		<comments>https://www.softwareace.cn/?p=1658#comments</comments>
		<pubDate>Thu, 15 Jun 2017 08:24:50 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1658</guid>
		<description><![CDATA[1.新建 compose_action_bar_layout.xml [crayon-69ec675896d1 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>1.新建 compose_action_bar_layout.xml</p><pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"&gt;

    &lt;Button
        android:id="@+id/compose_home_btn"
        style="@style/ActionMode.Button.Left"
        android:text="@string/cancel_action" /&gt;

    &lt;FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toStartOf="@+id/compose_send_btn"
        android:layout_toEndOf="@+id/compose_home_btn"
        android:layout_marginStart="@dimen/compose_account_from_margin"
        android:layout_marginEnd="@dimen/compose_account_from_margin"
        android:layout_centerInParent="true"&gt;

        &lt;include layout="@layout/compose_from" /&gt;

    &lt;/FrameLayout&gt;


    &lt;Button
        android:id="@+id/compose_send_btn"
        style="@style/ActionMode.Button.Right"
        android:text="@string/compose_send" /&gt;

&lt;/RelativeLayout&gt;</pre><p>2.修改 AndroidManifest.xml</p><pre class="crayon-plain-tag">&lt;activity
            android:name="com.kingsoft.mail.compose.ComposeActivity"
            android:label="@string/app_name"
            android:theme="@style/ComposeTheme"
&lt;/activity&gt;</pre><p>3.修改 styles3.xml</p><pre class="crayon-plain-tag">&lt;style name="ComposeTheme" parent="@miui:Theme.Light.HidePopupArrow"&gt;
        &lt;item name="android:actionOverflowButtonStyle"&gt;@style/OverflowButtonStyle&lt;/item&gt;
        &lt;!-- &lt;item name="android:spinnerDropDownItemStyle"&gt;@style/spinnerDropDownItemStyle&lt;/item&gt;--&gt;
        &lt;item name="android:actionBarStyle"&gt;@style/miui.ActionBar&lt;/item&gt;
    &lt;/style&gt;</pre><p>4.修改 ComposeActivity.java</p><pre class="crayon-plain-tag">private void initActionBar() {
		// compose_action_bar_layout
		final ActionBar actionBar = this.getActionBar();
		if (actionBar == null) {
			return;
		}

		final LayoutInflater inflater = LayoutInflater.from(actionBar
				.getThemedContext());
		RelativeLayout ll = (RelativeLayout) inflater.inflate(
				R.layout.compose_action_bar_layout, null);
		actionBar.setCustomView(ll);
        final int mask = ActionBar.DISPLAY_SHOW_CUSTOM;
        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
                mask);
｝</pre><p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1658</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>设置actionBar 背景和字体颜色</title>
		<link>https://www.softwareace.cn/?p=1656</link>
		<comments>https://www.softwareace.cn/?p=1656#comments</comments>
		<pubDate>Thu, 15 Jun 2017 03:00:55 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[andriod]]></category>

		<guid isPermaLink="false">http://www.softwareace.cn/?p=1656</guid>
		<description><![CDATA[[crayon-69ec675896fa9234886228/] &#160;]]></description>
				<content:encoded><![CDATA[<p></p><pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;resources&gt;
    &lt;style name="miui.ActionBar" parent="@miui:style/Widget.ActionBar"&gt;
        &lt;item name="android:background"&gt;@color/miui_theme_color&lt;/item&gt;
        &lt;item name="android:titleTextStyle"&gt;@style/miui.ActionBarTextStyle&lt;/item&gt;
    &lt;/style&gt;

    &lt;style name="miui.ActionBarTextStyle" parent="@miui:style/TextAppearance.WindowTitle"&gt;
        &lt;item name="android:textColor"&gt;@color/miui_actionbar_text_color&lt;/item&gt;
    &lt;/style&gt;
&lt;/resources&gt;</pre><p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.softwareace.cn/?feed=rss2&#038;p=1656</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
