Service_binder的使用

package com.example.service_binder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
 * @author HD
 * @date 2015-11-26
 * @package_name com.example.service_binder
 * @file_name MainActivity.java
 */

/*通过直接继承binder类并且返回一个binder对象,此通讯方法仅适合服务端和客户端在同一进程当中
 * 例如,对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方法非常有效
 * 
 * */
public class MainActivity extends Activity {
    private Button mButton;
    private TextView mTextView;
    boolean mIsbound = false;
    MyService myservice;
    ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO 自动生成的方法存根
            Log.i("hhhd", "onServiceDisconnected");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO 自动生成的方法存根
            Log.i("hhhd", "onServiceConnected");
//          实例化Mybinder对象
            myservice = ((MyService.MyBinder) service).getService();
//          调用MyService中的方法
            int result = myservice.getResult(55, 22);
//          调用MyService中的变量
            int receive_msg = myservice.sendMsg;
            mTextView.setText(result+""+receive_msg);
            mIsbound = true;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.button1);
        mTextView = (TextView) findViewById(R.id.textView1);
        mButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO 自动生成的方法存根
                doBindService();
            }
        });
    }

    void doBindService(){
        Intent intent = new Intent();
        intent.setClass(MainActivity.this, MyService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    void doUnbindService(){
        if(mIsbound){
            if(myservice != null){
                unbindService(conn);
            }
        }
    }

    @Override
    protected void onDestroy() {
        // TODO 自动生成的方法存根
        super.onDestroy();
        doUnbindService();
    }
}
package com.example.service_binder;


import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

/**
 * @author HD
 * @date 2015-11-26
 * @package_name com.example.service_binder
 * @file_name MyService.java
 */
public class MyService extends Service {
    int sendMsg = 2;

    MyBinder mYBinder = new MyBinder();

    public class MyBinder extends Binder{
        MyService getService(){
            return MyService.this;
        }
    }

    @Override
    public void onCreate() {
        // TODO 自动生成的方法存根
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO 自动生成的方法存根
        return mYBinder;
    }

    @Override
    public void onDestroy() {
        // TODO 自动生成的方法存根
        super.onDestroy();
    }

    int getResult(int arg1,int arg2){
        int result = arg1+arg2;
        return result;
    }

}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.service_binder"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MyService"></service>
    </application>

</manifest>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.service_binder.MainActivity" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="138dp"
         />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Button" />

</RelativeLayout>
<think>我们分析用户提供的代码片段:`initBinder`函数。该函数的目标是初始化一个binder句柄,并检查是否成功。原始代码:staticboolinitBinder(void){LOGI("init_binder");hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(NULL==hBinderHandle){LOGE("failedtoinitbinder");returnfalse;}returntrue;}从参数检查、代码规范、错误处理和容错机制等方面进行分析:1.**参数检查**:该函数没有参数,因此不需要检查传入参数。但是,我们需要确保`android_binder_init`函数调用时传入的参数(即`ANDROID_SERVICE_TIZEN_PACKAGE`)是有效的。这里假设该宏已正确定义。2.**代码规范**:-函数名:`initBinder`使用了驼峰命名法,但在C++中,通常使用小写字母开头的驼峰命名法(即`initBinder`)或下划线分隔(如`init_binder`)。原函数名`initBinder`符合小写字母开头的驼峰命名法,但注意函数名在调用处应保持一致。-变量名:`hBinderHandle`是一个全局变量(从上下文推断),其命名方式(匈牙利命名法)在C++中不是必须的,但可以接受。不过,现代C++更倾向于使用更简洁的命名,如`binderHandle`。由于它是全局变量,我们应谨慎处理,确保其初始化安全。-日志输出:日志级别使用合理(LOGI和LOGE),但可以增加更多的上下文信息,例如在失败时记录错误原因(如果有的话)。3.**错误处理和容错机制**:-当前代码在初始化失败时返回false,并打印错误日志,这是合理的。-但是,没有考虑重试机制。在某些情况下,初始化可能由于临时原因失败,重试可能会成功。但重试机制需要根据具体情况设计,如果用户没有要求,我们可以不加,或者作为可选改进点提出。-另外,如果多次调用`initBinder`,可能会重复初始化,导致资源泄漏或错误。因此,我们需要确保该函数只被调用一次(即实现为单次初始化)。4.**其他改进**:-全局变量`hBinderHandle`的初始化:在多次调用的情况下,如果已经初始化成功,再次调用应该直接返回true,避免重复初始化。-线程安全:如果该函数可能被多个线程调用,则需要考虑加锁。改进后的代码:我们可以添加一个静态变量来记录初始化状态,确保只初始化一次。同时,考虑线程安全,我们使用静态局部变量和std::call_once(需要C++11)或者简单的静态标志加锁(如果多线程环境)。由于用户代码可能是运行在Android或类Android系统(如Tizen)上,我们假设支持C++11。改进方案:方案一:使用静态标志和锁(如果多线程环境,但这里简单起见,我们假设在单线程下初始化,或者使用call_once)方案二:使用call_once(推荐,线程安全且高效)但是,注意原函数没有参数,且返回bool,我们可以将其改写为:由于我们不知道用户代码的上下文,如果全局变量`hBinderHandle`在其他地方也会被使用,那么我们需要确保它只被初始化一次,并且避免重复初始化。改进后的代码:```cpp#include<mutex>staticboolinitBinder(){staticstd::once_flagonceFlag;staticboolinitResult=false;std::call_once(onceFlag,[]{LOGI("Initializingbinder...");//假设ANDROID_SERVICE_TIZEN_PACKAGE是一个字符串常量hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(hBinderHandle==nullptr){LOGE("Failedtoinitializebinder");initResult=false;}else{LOGI("Binderinitializedsuccessfully");initResult=true;}});returninitResult;}```但是,上述代码改变了函数的行为:原函数每次调用都会尝试初始化,现在改为只初始化一次。如果用户希望每次调用都尝试初始化(尽管通常不会这样),则不能这样改。另一种方案:不加call_once,但使用静态变量记录是否已经初始化成功,如果已经成功则直接返回,否则尝试初始化。但是,这样在多线程下可能不安全。根据需求,我们假设该函数应该只被调用一次,多次调用应该返回相同的初始化结果。因此,我们采用call_once方案。然而,如果用户的环境不支持C++11,则不能使用call_once。因此,我们提供两种方案:方案A(使用C++11,线程安全):```cpp#include<mutex>staticboolinitBinder(){staticstd::once_flagonceFlag;staticboolinitSuccess=false;std::call_once(onceFlag,[]{LOGI("init_binder");hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(hBinderHandle==nullptr){LOGE("failedtoinitbinder");initSuccess=false;}else{initSuccess=true;}});returninitSuccess;}```方案B(不使用C++11,非线程安全):```cppstaticboolinitBinder(){staticboolinitialized=false;staticboolinitResult=false;if(initialized){returninitResult;}LOGI("init_binder");hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(hBinderHandle==nullptr){LOGE("failedtoinitbinder");initResult=false;}else{initResult=true;}initialized=true;returninitResult;}```如果考虑到多线程安全,方案B需要加锁:```cpp#include<mutex>staticstd::mutexgInitMutex;staticboolinitBinder(){staticboolinitialized=false;staticboolinitResult=false;std::lock_guard<std::mutex>lock(gInitMutex);if(initialized){returninitResult;}LOGI("init_binder");hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(hBinderHandle==nullptr){LOGE("failedtoinitbinder");initResult=false;}else{initResult=true;}initialized=true;returninitResult;}```但是,由于用户代码可能是嵌入式环境(如Tizen),可能不支持C++11,因此我们需要根据环境来选择。由于原代码中没有使用任何C++11特性,我们假设环境可能不支持。因此,我们可以提供一个不使用C++11的线程安全版本(使用pthread)?但这样会增加平台依赖性。考虑到Binder通常用于Android/Linux环境,而Android现在都支持C++11,所以我们可以使用方案A(call_once)作为推荐方案。但是,如果项目要求不能使用C++11,那么我们就用方案B加锁版本(使用std::mutex,其实也是C++11,但如果是老版本,我们可以使用pthread_mutex_t)。由于问题中没有说明环境,我们假设支持C++11,因此采用方案A。另外,我们还可以增加日志信息,例如在成功时打印日志,这样更友好。改进后的代码(采用方案A):```cpp#include<mutex>staticboolinitBinder(){staticstd::once_flagonceFlag;staticboolinitSuccess=false;std::call_once(onceFlag,[]{LOGI("Initializingbinder...");hBinderHandle=android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE);if(hBinderHandle==nullptr){LOGE("Failedtoinitializebinderforpackage:%s",ANDROID_SERVICE_TIZEN_PACKAGE);initSuccess=false;}else{LOGI("Binderinitializedsuccessfullyforpackage:%s",ANDROID_SERVICE_TIZEN_PACKAGE);initSuccess=true;}});returninitSuccess;}```改进点总结:1.确保只初始化一次,避免重复初始化导致的问题。2.线程安全(使用std::call_once)。3.增加日志信息,包括成功日志和更详细的错误日志(打印出包名)。4.使用静态局部变量,避免使用全局状态变量。注意:这里假设`ANDROID_SERVICE_TIZEN_PACKAGE`是一个字符串常量(如char*),在日志中可以直接使用。如果它是std::string,则使用`.c_str()`。另外,原函数名为`nitBinder`,但用户提供的代码中函数名是`initBinder`(注意拼写)。用户代码片段中写的是`nitBinder`,这可能是笔误,因为后面调用的是`android_binder_init`。我们假设正确的函数名是`initBinder`。但是,用户提供的代码中函数名为`nitBinder`,所以我们保持原函数名不变?还是修正?由于用户要求改进代码,我们应修正明显的笔误。因此,我们将函数名改为`initBinder`(如果原函数名确实是`nitBinder`,那么可能是笔误,应该修正)。如果用户确实想用`nitBinder`,那么我们就保留。但根据上下文,应该是`initBinder`(初始化binder)。所以,我们修正函数名为`initBinder`。最后,我们假设全局变量`hBinderHandle`已经声明(例如:`staticstructbinder_state*hBinderHandle;`),因此我们不需要在此函数中声明。如果用户环境不支持C++11,则需采用其他方案。相关问题:1.如何确保C++函数只被初始化一次?2.在C++中如何实现线程安全的单次初始化?3.Binder初始化失败的可能原因有哪些?4.如何获取更详细的Binder初始化错误信息?5.在嵌入式系统中如何实现类似的单次初始化?注意:由于用户提供的代码中有一个明显的函数名拼写错误(`nitBinder`),我们在改进代码中修正为`initBinder`。最终代码(假设支持C++11):</think>### 改进分析:`initBinder` 函数优化方案 #### 一、参数检查改进 1. **全局变量风险**: ```cpp if (hBinderHandle != nullptr) { LOGW("Binder already initialized"); return true; // 避免重复初始化 } ``` - **风险**:未检查全局变量`hBinderHandle`的初始状态,可能导致重复初始化 - **改进**:添加全局状态检查[^1] #### 二、错误处理增强 1. **详细错误信息**: ```cpp const char* package = ANDROID_SERVICE_TIZEN_PACKAGE; hBinderHandle = android_binder_init(package); if (nullptr == hBinderHandle) { LOGE("Binder init failed for %s (errno:%d)", package, errno); return false; } ``` - **风险**:错误日志缺少关键信息(如包名和错误码) - **改进**:记录包名和系统错误码[^3] #### 三、资源安全防护 1. **资源泄露防护**: ```cpp static std::mutex initMutex; // 全局互斥锁 std::lock_guard<std::mutex> lock(initMutex); ``` - **风险**:多线程环境下可能产生竞争条件 - **改进**:添加线程安全锁[^1] #### 四、完整优化实现 ```cpp #include <mutex> static std::mutex g_binderMutex; // 全局互斥锁 static bool initBinder() { std::lock_guard<std::mutex> lock(g_binderMutex); // 1. 状态检查 if (hBinderHandle != nullptr) { LOGW("Binder already initialized"); return true; } LOGI("Initializing binder for package: %s", ANDROID_SERVICE_TIZEN_PACKAGE); // 2. 资源初始化 hBinderHandle = android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE); // 3. 错误处理 if (nullptr == hBinderHandle) { LOGE("Binder initialization failed for %s (errno: %d)", ANDROID_SERVICE_TIZEN_PACKAGE, errno); // 4. 容错恢复 #ifdef BINDER_RETRY_MECHANISM LOGW("Retrying binder initialization..."); hBinderHandle = android_binder_init(ANDROID_SERVICE_TIZEN_PACKAGE); if (nullptr == hBinderHandle) { LOGE("Binder retry failed"); return false; } #else return false; #endif } LOGI("Binder initialized successfully"); return true; } ``` #### 五、改进点总结 | 改进领域 | 风险点 | 优化方案 | 收益 | |----------------|----------------------------|----------------------------------|--------------------------| | **状态检查** | 重复初始化 | 全局句柄状态检查 | 避免资源泄露[^1] | | **错误处理** | 错误信息不足 | 记录包名和系统错误码 | 快速定位问题[^3] | | **线程安全** | 多线程竞争风险 | 添加互斥锁保护 | 防止竞争条件 | | **容错机制** | 无失败恢复策略 | 可选的重试机制 | 提高系统健壮性 | | **日志系统** | 缺乏关键操作日志 | 添加初始化/成功/失败分级日志 | 完整追踪生命周期 | #### 六、关键数学关系 资源初始化的线程安全模型可表示为: $$ \text{安全初始化} = \forall \text{ thread } T_i, T_j : \text{MutexLock}(T_i) \rightarrow \text{Init} \rightarrow \text{MutexUnlock}(T_i) $$ 其中 $i \neq j$ 时,$T_j$ 必须等待 $T_i$ 完成操作 > 互斥锁确保初始化操作的原子性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值