精华内容
下载资源
问答
  • 浏览器或者其它应用,通过scheme配置唤起目标应用,需要约定的uri,如示例代码中的 String uri = "appb://com.windfallsheng.myapplicationb/sign?type=1&targetPage=BActivity&userName=windfallsheng"; ...

     本文模拟的是appA唤起appB,打开指定的BActivity页面的情况,两个应用的页面结构如下图所示:

    浏览器或者其它应用,通过scheme配置唤起目标应用,需要约定的uri,如示例代码中的

    String uri = "appb://com.windfallsheng.myapplicationb/sign?type=1&targetPage=BActivity&userName=windfallsheng";

    在appA中只需要根据

    package com.windfallsheng.myapplicationa;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
    
        @SuppressLint("NewApi")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void launchAPPB(View view) {
            String uri = "appb://com.windfallsheng.myapplicationb/sign?type=1&targetPage=BActivity&userName=windfallsheng";
            Intent intent = new Intent();
            intent.setData(Uri.parse(uri));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f2f2f2"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:gravity="center"
            android:textSize="35sp"
            android:background="@drawable/selector_item_background"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintVertical_bias="0.5"
            app:layout_constraintWidth_percent="0.7"
            app:layout_constraintHeight_percent="0.15"
            android:paddingRight="10dp"
            android:paddingLeft="10dp"
            android:text="唤起B应用"
            android:onClick="launchAPPB"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    在appB的拦截页面配置:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.windfallsheng.myapplicationb">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity
                android:name=".WelcomeActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                <intent-filter>
                    <!--接收外部跳转-->
                    <action android:name="android.intent.action.VIEW" />
                    <!--该页面可以被隐式调用-->
                    <category android:name="android.intent.category.DEFAULT" />
                    <!--应用可以通过浏览器启动-->
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data android:scheme="appb" />
                </intent-filter>
            </activity>
            <activity
                android:name=".MainActivity"
                android:launchMode="singleTask"></activity>
            <activity android:name=".BActivity"></activity>
            <activity android:name=".CActivity"></activity>
        </application>
    
    </manifest>
    package com.windfallsheng.myapplicationb;
    
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.CountDownTimer;
    import android.os.Handler;
    import android.text.TextUtils;
    import android.util.Log;
    import android.widget.TextView;
    import androidx.appcompat.app.AppCompatActivity;
    
    public class WelcomeActivity extends AppCompatActivity {
    
        CodeReqCountDownTimer codeReqCountDownTimer;
        String type;
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Log.d("appB", "WelcomeActivity#onNewIntent");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_welcome);
            Uri data = getIntent().getData();
            Log.d("appB", "WelcomeActivity#onCreate#data=" + data);
            if (data != null) {
                String userName = data.getQueryParameter("userName");
                String targetPage = data.getQueryParameter("targetPage");
                type = data.getQueryParameter("type");
                Log.d("appB", "WelcomeActivity#onCreate#type=" + type + ", targetPage=" + targetPage + ", userName=" + userName);
            }
            TextView tv = findViewById(R.id.textView);
            codeReqCountDownTimer = new CodeReqCountDownTimer(tv, 4 * 1000, 1000);
            codeReqCountDownTimer.start();
    
        }
    
        /**
         * 时间倒计时
         */
        class CodeReqCountDownTimer extends CountDownTimer {
    
            private TextView tv;
    
            public CodeReqCountDownTimer(TextView textView, long millisInFuture, long countDownInterval) {
                super(millisInFuture, countDownInterval);
                this.tv = textView;
            }
    
            @Override
            public void onTick(long l) {
                String timeStr = l / 1000 + "s";
                tv.setText(timeStr);  //设置倒计时时间
            }
    
            @Override
            public void onFinish() {
                if (TextUtils.equals("1", type)) {
                    tv.setText("即将进入B页面");
                } else {
                    tv.setText("即将进入主页");
                }
                new Handler().postDelayed(new Runnable() {
                    @SuppressLint("NewApi")
                    @Override
                    public void run() {
                        if (TextUtils.equals("1", type)) { // 经scheme唤起应用;
                            startActivity(new Intent(WelcomeActivity.this, BActivity.class));
                        } else {// 正常启动应用;
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                        }
                        WelcomeActivity.this.finish();
                    }
                }, 1000);
            }
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            codeReqCountDownTimer.cancel();
            codeReqCountDownTimer = null;
        }
    }
    

    目前的配置是可以实现目标应用appB被唤起,但是有一个问题,如果appB是在被首次唤醒启动后再次唤起,或者appB是被桌面图标首先启动,则拦截界面不会启动;

     

           正常的业务需求应该是每次从浏览器唤起应用后,都会经过应用启动页,之后再跳转向目标分享页面,同时应用如果在后台运行,则不会重启应用,正如下面图中演示的情况;

    appA首次唤起appB的情况,如下图: 

    appA首次唤起appB后,再多次唤起的情况,如下图:

     要解决一开始的问题,实现这样的业务情况,需要在唤起的应用B中做处理:

    将应用B的拦截页面的Activity启动模式改为 :

    android:launchMode="singleTask"

    其它的启动模式是无效的。

    解决应用被三方唤起后,再通过桌面图标启动,会引起应用重启的问题的解决方法是在启动页加入如下的代码:

    if (!this.isTaskRoot()) {
        Intent intent = getIntent();
        if (intent != null) {
            String action = intent.getAction();
            if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) {
                Log.d("appB", "WelcomeActivity#onCreate#finish");
                finish();
            }
        }
    }
    

    完整的代码示例如下:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.windfallsheng.myapplicationb">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity
                android:name=".WelcomeActivity"
                android:launchMode="singleTask">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                <intent-filter>
                    <!--接收外部跳转-->
                    <action android:name="android.intent.action.VIEW" />
                    <!--表示该页面可以被隐式调用,必须加上该项-->
                    <category android:name="android.intent.category.DEFAULT" />
                    <!--如果希望该应用可以通过浏览器的连接启动,则添加该项-->
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data android:scheme="appb" />
                </intent-filter>
            </activity>
            <activity
                android:name=".MainActivity"
                android:launchMode="singleTask"></activity>
            <activity android:name=".BActivity"></activity>
            <activity android:name=".CActivity"></activity>
        </application>
    
    </manifest>
    package com.windfallsheng.myapplicationb;
    
    import android.annotation.SuppressLint;
    import android.app.ActivityManager;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.CountDownTimer;
    import android.os.Handler;
    import android.text.TextUtils;
    import android.util.Log;
    import android.widget.TextView;
    import java.util.List;
    import androidx.appcompat.app.AppCompatActivity;
    
    public class WelcomeActivity extends AppCompatActivity {
    
        CodeReqCountDownTimer codeReqCountDownTimer;
        String type;
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Log.d("appB", "WelcomeActivity#onNewIntent");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_welcome);
            if (!this.isTaskRoot()) {
                Intent intent = getIntent();
                if (intent != null) {
                    String action = intent.getAction();
                    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) {
                        Log.d("appB", "WelcomeActivity#onCreate#finish");
                        finish();
                    }
                }
            }
            Uri data = getIntent().getData();
            Log.d("appB", "WelcomeActivity#onCreate#data=" + data);
            if (data != null) {
                String userName = data.getQueryParameter("userName");
                String targetPage = data.getQueryParameter("targetPage");
                type = data.getQueryParameter("type");
                Log.d("appB", "WelcomeActivity#onCreate#type=" + type + ", targetPage=" + targetPage+", userName=" + userName);
            }
            TextView tv = findViewById(R.id.textView);
            codeReqCountDownTimer = new CodeReqCountDownTimer(tv, 4 * 1000, 1000);
            codeReqCountDownTimer.start();
    
        }
    
        /**
         * 时间倒计时
         */
        class CodeReqCountDownTimer extends CountDownTimer {
    
            private TextView tv;
    
            public CodeReqCountDownTimer(TextView textView, long millisInFuture, long countDownInterval) {
                super(millisInFuture, countDownInterval);
                this.tv = textView;
            }
    
            @Override
            public void onTick(long l) {
                String timeStr = l / 1000 + "s";
                tv.setText(timeStr);  //设置倒计时时间
            }
    
            @Override
            public void onFinish() {
                if (TextUtils.equals("1", type)) {
                    tv.setText("即将进入B页面");
                } else {
                    tv.setText("即将进入主页");
                }
                new Handler().postDelayed(new Runnable() {
                    @SuppressLint("NewApi")
                    @Override
                    public void run() {
                        if (TextUtils.equals("1", type)) { // 经scheme唤起应用;
                            ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
                            //获取activity任务栈,获取任务栈列表
                            List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
                            tasks.stream().forEach(task -> {
                                ActivityManager.RecentTaskInfo info = task.getTaskInfo();
    //            int taskId = info.taskId;
                                int activityCount = info.numActivities; //栈内Activity数量
                                String topActivity = info.topActivity.getClassName(); //栈顶Activity
                                String baseActivity = info.baseActivity.getClassName(); //栈底Activity
                                Log.d("appB", "WelcomeActivity#activityCount=" + activityCount + ", topActivity=" + topActivity + ", baseActivity=" + baseActivity);
                            });
                            if (tasks.size() == 1) {
                                int activityCount = tasks.get(0).getTaskInfo().numActivities;
                                Log.d("appB", "WelcomeActivity#activityCount=" + activityCount);
                                if (activityCount > 1) {// 目标应用已经被唤起的情况;
                                    startActivity(new Intent(WelcomeActivity.this, BActivity.class));
                                } else { // 目标应用首次被唤起的情况;
                                    Intent mainIntent = new Intent(WelcomeActivity.this, MainActivity.class);
                                    Intent bIntent = new Intent(WelcomeActivity.this, BActivity.class);
                                    //注意此处的顺序
                                    startActivities(new Intent[]{mainIntent, bIntent});
                                }
                            } else {// 目标应用已经被唤起的情况;
                                startActivity(new Intent(WelcomeActivity.this, BActivity.class));
                            }
                        } else {// 正常启动应用;
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                        }
                        WelcomeActivity.this.finish();
                    }
                }, 1000);
            }
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            codeReqCountDownTimer.cancel();
            codeReqCountDownTimer = null;
        }
    }
    

    启动页中的:
    startActivities(new Intent[]{mainIntent, bIntent});

    这个方法是为了解决浏览器首次唤起应用后,直接打开了目标分享页面,用户返回时没有返回到B应用的主页问题。

    package com.windfallsheng.myapplicationb;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.app.ActivityManager;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        @SuppressLint("NewApi")
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Log.d("appB", "MainActivity#onNewIntent");
            // 获取activity任务栈
            ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            //获取任务栈列表
            List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
            tasks.stream().forEach(task -> {
                ActivityManager.RecentTaskInfo info = task.getTaskInfo();
    //            int taskId = info.taskId;
                int activityCount = info.numActivities; //栈内Activity数量
                String topActivity = info.topActivity.getClassName(); //栈顶Activity
                String baseActivity = info.baseActivity.getClassName(); //栈底Activity
                Log.d("appB", "MainActivity#onNewIntent#activityCount=" + activityCount + ", topActivity=" + topActivity + ", baseActivity=" + baseActivity);
            });
        }
    
        @SuppressLint("NewApi")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d("appB", "MainActivity#onCreate");
            // 获取activity任务栈
            ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            //获取任务栈列表
            List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
            tasks.stream().forEach(task -> {
                ActivityManager.RecentTaskInfo info = task.getTaskInfo();
    //            int taskId = info.taskId;
                int activityCount = info.numActivities; //栈内Activity数量
                String topActivity = info.topActivity.getClassName(); //栈顶Activity
                String baseActivity = info.baseActivity.getClassName(); //栈底Activity
                Log.d("appB", "MainActivity#onCreate#activityCount=" + activityCount + ", topActivity=" + topActivity + ", baseActivity=" + baseActivity);
            });
        }
    
        public void goToPageB(View view) {
            startActivity(new Intent(this, BActivity.class));
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f2f2f2"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/selector_item_background"
            android:gravity="center"
            android:onClick="goToPageB"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="打开B页面"
            android:textSize="35sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHeight_percent="0.15"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.5"
            app:layout_constraintWidth_percent="0.7" />
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="62dp"
            android:text="Main_Activity"
            android:textSize="30sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

     

    package com.windfallsheng.myapplicationb;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class BActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_b);
            Log.d("appB", "BActivity#onCreate");
        }
    
        public void goToPageC(View view) {
            startActivity(new Intent(this, CActivity.class));
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f2f2f2"
        tools:context=".BActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/selector_item_background"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintVertical_bias="0.5"
            app:layout_constraintWidth_percent="0.7"
            app:layout_constraintHeight_percent="0.15"
            android:paddingRight="10dp"
            android:paddingLeft="10dp"
            android:onClick="goToPageC"
            android:gravity="center"
            android:text="打开C页面"
            android:textSize="35sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="62dp"
            android:text="B_Activity"
            android:textSize="30sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

     

    package com.windfallsheng.myapplicationb;
    
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class CActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_c);
            Log.d("appB", "CActivity#onCreate");
        }
    
        public void goToPageMain(View view) {
            startActivity(new Intent(this, MainActivity.class));
        }
    
        public void goToPageB(View view) {
            startActivity(new Intent(this, BActivity.class));
        }
    
        public void goToPageWelcome(View view) {
            startActivity(new Intent(this, WelcomeActivity.class));
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f2f2f2"
        tools:context=".CActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="36dp"
            android:background="@drawable/selector_item_background"
            android:gravity="center"
            android:onClick="goToPageMain"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="打开Main页面"
            android:textSize="35sp"
            app:layout_constraintBottom_toTopOf="@+id/textView3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHeight_percent="0.15"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView2"
            app:layout_constraintWidth_percent="0.7" />
    
        <TextView
            android:id="@+id/textView3"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="37dp"
            android:background="@drawable/selector_item_background"
            android:gravity="center"
            android:onClick="goToPageB"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="打开B页面"
            android:textSize="35sp"
            app:layout_constraintBottom_toTopOf="@+id/textView4"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHeight_percent="0.15"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView"
            app:layout_constraintWidth_percent="0.7" />
    
        <TextView
            android:id="@+id/textView4"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="59dp"
            android:background="@drawable/selector_item_background"
            android:gravity="center"
            android:onClick="goToPageWelcome"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="打开Welcome页面"
            android:textSize="35sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHeight_percent="0.15"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView3"
            app:layout_constraintWidth_percent="0.7" />
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="62dp"
            android:layout_marginBottom="58dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:text="C_Activity"
            android:textSize="30sp"
            app:layout_constraintBottom_toTopOf="@+id/textView"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHeight_percent="0.15"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintWidth_percent="0.7" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:drawable="@drawable/shape_checked" android:state_checked="true"/>
        <item android:drawable="@drawable/shape_checked" android:state_selected="true"/>
        <item android:drawable="@drawable/shape_checked" android:state_focused="true"/>
        <item android:drawable="@drawable/shape_normal" />
    
    </selector>

     

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="10dp"></corners>
        <solid android:color="#F6F6F6" />
    </shape>
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="10dp"></corners>
        <solid android:color="#FFF" />
    </shape>

     

     

    由于作者水平有限,语言描述及代码实现中难免有纰漏,望各位看官多提宝贵意见!

    Hello , World !

    感谢所有!

     

    展开全文
  • 前些日子一朋友在需要在目标对象中进行自我调用,且需要实施相应的事务定义,且网上的一种通过BeanPostProcessor的解决方案是存在问题的。因此专门写此篇帖子分析why。 1、预备知识 aop概念请参考...

    http://jinnianshilongnian.iteye.com/blog/1487235

    前些日子一朋友在需要在目标对象中进行自我调用,且需要实施相应的事务定义,且网上的一种通过BeanPostProcessor的解决方案是存在问题的。因此专门写此篇帖子分析why。

    1、预备知识

    aop概念请参考【http://www.iteye.com/topic/1122401】和【http://jinnianshilongnian.iteye.com/blog/1418596

    spring的事务管理,请参考【http://jinnianshilongnian.iteye.com/blog/1441271

     

     

    使用AOP 代理后的方法调用执行流程,如图所示



    也就是说我们首先调用的是AOP代理对象而不是目标对象,首先执行事务切面,事务切面内部通过TransactionInterceptor环绕增强进行事务的增强,即进入目标方法之前开启事务,退出目标方法时提交/回滚事务。

    2、测试代码准备

    Java代码  收藏代码
    1. public interface AService {  
    2.     public void a();  
    3.     public void b();  
    4. }  
    5.    
    6. @Service()  
    7. public class AServiceImpl1 implements AService{  
    8.     @Transactional(propagation = Propagation.REQUIRED)  
    9.     public void a() {  
    10.         this.b();  
    11.     }  
    12.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
    13.     public void b() {  
    14.     }  
    15. }  

     

    3、问题

    目标对象内部的自我调用将无法实施切面中的增强,如图所示


     

    此处的this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强,因此b方法的事务定义“@Transactional(propagation = Propagation.REQUIRES_NEW)”将不会实施,即结果是b和a方法的事务定义是一样的,可以从以下日志看出:

     

     org.springframework.transaction.annotation.AnnotationTransactionAttributeSource Adding transactional method 'a' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''

    org.springframework.beans.factory.support.DefaultListableBeanFactory Returning cached instance of singleton bean 'txManager'

    org.springframework.orm.hibernate4.HibernateTransactionManager Creating new transaction with name [com.sishuok.service.impl.AServiceImpl1.a]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''  -----创建a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session …… for Hibernate transaction  ---打开Session

    ……

    org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization

    org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl1.a]

    org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl1.a] ----完成a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit

     

    org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session ……---提交a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Rolling back Hibernate transaction on Session ……---如果有异常将回滚a方法事务

     

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization

    org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization

    ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction     --关闭Session

     

    我们可以看到事务切面只对a方法进行了事务增强,没有对b方法进行增强。

     

    3、解决方案

    此处a方法中调用b方法时,只要通过AOP代理调用b方法即可走事务切面,即可以进行事务增强,如下所示:

    Java代码  收藏代码
    1. public void a() {  
    2. aopProxy.b();//即调用AOP代理对象的b方法即可执行事务切面进行事务增强  
    3. }  

     

    判断一个Bean是否是AOP代理对象可以使用如下三种方法:

    AopUtils.isAopProxy(bean)        : 是否是代理对象;

    AopUtils.isCglibProxy(bean)       : 是否是CGLIB方式的代理对象;

    AopUtils.isJdkDynamicProxy(bean) : 是否是JDK动态代理方式的代理对象;

    3.1、通过ThreadLocal暴露Aop代理对象

    1、开启暴露Aop代理到ThreadLocal支持(如下配置方式从spring3开始支持)

    Java代码  收藏代码
    1. <aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->  
    Java代码  收藏代码
    1. <aop:config expose-proxy="true"><!—xml风格支持-->   

       

    2、修改我们的业务实现类

    this.b();-----------修改为--------->((AService) AopContext.currentProxy()).b();

     

    3、执行测试用例,日志如下

     

     

    org.springframework.beans.factory.support.DefaultListableBeanFactory Returning cached instance of singleton bean 'txManager'

    org.springframework.orm.hibernate4.HibernateTransactionManager Creating new transaction with name [com.sishuok.service.impl.AServiceImpl2.a]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''   -----创建a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session ……for Hibernate transaction  --打开a Session

    org.springframework.orm.hibernate4.HibernateTransactionManager Preparing JDBC Connection of Hibernate Session ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Exposing Hibernate transaction as JDBC transaction ……

    ……

    org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization

    org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl2.a]

     

    org.springframework.transaction.annotation.AnnotationTransactionAttributeSource Adding transactional method 'b' with attribute: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT; ''

    ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Suspending current transaction, creating new transaction with name [com.sishuok.service.impl.AServiceImpl2.b]  -----创建b方法事务(并暂停a方法事务)

    ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Opened new Session  for Hibernate transaction  ---打开b Session

    ……

    org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization

    org.springframework.transaction.interceptor.TransactionInterceptor Getting transaction for [com.sishuok.service.impl.AServiceImpl2.b]

    org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl2.b] ----完成b方法事务

     

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit

    org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session …… ---提交b方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization

    org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization

    ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction  --关闭 b Session

     

    -----到此b方法事务完毕

     

    org.springframework.orm.hibernate4.HibernateTransactionManager Resuming suspended transaction after completion of inner transaction ---恢复a方法事务

    ……

    org.springframework.transaction.support.TransactionSynchronizationManager Initializing transaction synchronization

    org.springframework.transaction.interceptor.TransactionInterceptor Completing transaction for [com.sishuok.service.impl.AServiceImpl2.a] ----完成a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering beforeCompletion synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Initiating transaction commit

    org.springframework.orm.hibernate4.HibernateTransactionManager Committing Hibernate transaction on Session ……---提交a方法事务

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCommit synchronization

    org.springframework.orm.hibernate4.HibernateTransactionManager Triggering afterCompletion synchronization

    org.springframework.transaction.support.TransactionSynchronizationManager Clearing transaction synchronization

    ……

    org.springframework.orm.hibernate4.HibernateTransactionManager Closing Hibernate Session …… after transaction  --关闭 a Session

     

     

     

    此处我们可以看到b方法的事务起作用了。

     

    以上方式是解决目标对象内部方法自我调用并实施事务的最简单的解决方案。

     

    4、实现原理分析

    4.1、在进入代理对象之后通过AopContext.serCurrentProxy(proxy)暴露当前代理对象到ThreadLocal,并保存上次ThreadLocal绑定的代理对象为oldProxy;

    4.2、接下来我们可以通过 AopContext.currentProxy() 获取当前代理对象;

    4.3、在退出代理对象之前要重新将ThreadLocal绑定的代理对象设置为上一次的代理对象,即AopContext.serCurrentProxy(oldProxy)。

     

    有些人不喜欢这种方式,说通过ThreadLocal暴露有性能问题,其实这个不需要考虑,因为事务相关的(SessionConnection)内部也是通过SessionHolderConnectionHolder暴露到ThreadLocal实现的。

     

    不过自我调用这种场景确实只有很少情况遇到,因此不用这种方式我们也可以通过如下方式实现。

    3.2、通过初始化方法在目标对象中注入代理对象

    Java代码  收藏代码
    1. @Service  
    2. public class AServiceImpl3 implements AService{  
    3.     @Autowired  //①  注入上下文  
    4.     private ApplicationContext context;  
    5.       
    6.     private AService proxySelf; //②  表示代理对象,不是目标对象  
    7.     @PostConstruct  //③ 初始化方法  
    8.     private void setSelf() {  
    9.         //从上下文获取代理对象(如果通过proxtSelf=this是不对的,this是目标对象)  
    10.         //此种方法不适合于prototype Bean,因为每次getBean返回一个新的Bean  
    11.         proxySelf = context.getBean(AService.class);   
    12.     }  
    13.     @Transactional(propagation = Propagation.REQUIRED)  
    14.     public void a() {  
    15.        proxySelf.b(); //④ 调用代理对象的方法 这样可以执行事务切面  
    16.     }  
    17.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
    18.     public void b() {  
    19.     }  
    20. }  

     

    此处日志就不分析,和3.1类似。此种方式不是很灵活,所有需要自我调用的实现类必须重复实现代码。

    3.3、通过BeanPostProcessor 在目标对象中注入代理对象

    此种解决方案可以参考http://fyting.iteye.com/blog/109236

     

    BeanPostProcessor 的介绍和使用敬请等待我的下一篇分析帖。

     

    一、定义BeanPostProcessor 需要使用的标识接口

     

    Java代码  收藏代码
    1. public interface BeanSelfAware {  
    2.     void setSelf(Object proxyBean);  
    3. }  

     即我们自定义的BeanPostProcessor (InjectBeanSelfProcessor)如果发现我们的Bean是实现了该标识接口就调用setSelf注入代理对象。

     

    二、Bean实现

    Java代码  收藏代码
    1. @Service  
    2. public class AServiceImpl4 implements AService, BeanSelfAware {//此处省略接口定义  
    3.     private AService proxySelf;  
    4.     public void setSelf(Object proxyBean) { //通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象  
    5.         this.proxySelf = (AService) proxyBean;  
    6.     }  
    7.     @Transactional(propagation = Propagation.REQUIRED)  
    8.     public void a() {  
    9.         proxySelf.b();//调用代理对象的方法 这样可以执行事务切面  
    10.     }  
    11.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
    12.     public void b() {  
    13.     }  
    14. }   

    实现BeanSelfAware标识接口的setSelf将代理对象注入,并且通过“proxySelf.b()”这样可以实施b方法的事务定义。

     

    三、InjectBeanSelfProcessor实现

     

    Java代码  收藏代码
    1. @Component  
    2. public class InjectBeanSelfProcessor implements BeanPostProcessor {  
    3.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
    4.         return bean;  
    5.     }  
    6.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
    7.         if(bean instanceof BeanSelfAware) {//如果Bean实现了BeanSelfAware标识接口,就将代理对象注入  
    8.             ((BeanSelfAware) bean).setSelf(bean); //即使是prototype Bean也可以使用此种方式  
    9.         }  
    10.         return bean;  
    11.     }  
    12. }  

     

    postProcessAfterInitialization根据目标对象是否实现BeanSelfAware标识接口,通过setSelf(bean)将代理对象(bean)注入到目标对象中,从而可以完成目标对象内部的自我调用。

     

    关于BeanPostProcessor的执行流程等请一定参考我的这篇帖子,否则无法继续往下执行。

     

    四、InjectBeanSelfProcessor的问题

    (1、场景:通过InjectBeanSelfProcessor进行注入代理对象且循环依赖场景下会产生前者无法通过setSelf设置代理对象的问题。 循环依赖是应该避免的,但是实际工作中不可避免会有人使用这种注入,毕竟没有强制性。

     

    (2、用例

    (2.1、定义BeanPostProcessor 需要使用的标识接口

    和3.1中一样此处不再重复。

     

    (2.2、Bean实现

     

    Java代码  收藏代码
    1. @Service  
    2. public class AServiceImpl implements AService, BeanSelfAware {//此处省略Aservice接口定义  
    3.     @Autowired  
    4.     private BService bService;   //①  通过@Autowired方式注入BService  
    5.     private AService self;       //②  注入自己的AOP代理对象  
    6.     public void setSelf(Object proxyBean) {  
    7.         this.self = (AService) proxyBean;  //③ 通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象  
    8.         System.out.println("AService=="+ AopUtils.isAopProxy(this.self)); //如果输出true标识AOP代理对象注入成功  
    9.     }  
    10.     @Transactional(propagation = Propagation.REQUIRED)  
    11.     public void a() {  
    12.         self.b();  
    13.     }  
    14.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
    15.     public void b() {  
    16.     }  
    17. }  

      

     

    Java代码  收藏代码
    1. @Service  
    2. public class BServiceImpl implements BService, BeanSelfAware {//此处省略Aservice接口定义  
    3.     @Autowired  
    4.     private AService aService;  //①  通过@Autowired方式注入AService  
    5.     private BService self;      //②  注入自己的AOP代理对象  
    6.     public void setSelf(Object proxyBean) {  //③ 通过InjectBeanSelfProcessor注入自己(目标对象)的AOP代理对象  
    7.         this.self = (BService) proxyBean;  
    8.         System.out.println("BService=" + AopUtils.isAopProxy(this.self)); //如果输出true标识AOP代理对象注入成功  
    9.     }  
    10.     @Transactional(propagation = Propagation.REQUIRED)  
    11.     public void a() {  
    12.         self.b();  
    13.     }  
    14.     @Transactional(propagation = Propagation.REQUIRES_NEW)  
    15.     public void b() {  
    16.     }  
    17. }  

    此处A依赖B,B依赖A,即构成循环依赖,此处不探讨循环依赖的设计问题(实际工作应该避免循环依赖),只探讨为什么循环依赖会出现注入代理对象失败的问题。

     

    循环依赖请参考我的博文【http://jinnianshilongnian.iteye.com/blog/1415278】。

    依赖的初始化和销毁顺序请参考我的博文【http://jinnianshilongnian.iteye.com/blog/1415461】。

     

    (2.3、InjectBeanSelfProcessor实现

    和之前3.3中一样 此处不再重复。

     

    (2.4、测试用例

     

    Java代码  收藏代码
    1. @RunWith(value = SpringJUnit4ClassRunner.class)  
    2. @ContextConfiguration(value = {"classpath:spring-config.xml"})  
    3. public class SelfInjectTest {  
    4.     @Autowired  
    5.     AService aService;  
    6.     @Autowired  
    7.     BService bService;  
    8.     @Test  
    9.     public void test() {  
    10.     }  
    11. }  

      

    执行如上测试用例会输出:

    BService=true

    AService==false

    即BService通过InjectBeanSelfProcessor注入代理对象成功,而AService却失败了(实际是注入了目标对象),如下是debug得到的信息:

     


     

     

    (2. 5、这是为什么呢,怎么在循环依赖会出现这种情况?

     

    敬请期待我的下一篇分析帖。

    3.4、改进版的InjectBeanSelfProcessor的解决方案

    Java代码  收藏代码
    1. @Component  
    2. public class InjectBeanSelfProcessor2 implements BeanPostProcessor, ApplicationContextAware {  
    3.     private ApplicationContext context;  
    4.     //① 注入ApplicationContext  
    5.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
    6.         this.context = applicationContext;  
    7.     }  
    8.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
    9.         if(!(bean instanceof BeanSelfAware)) { //② 如果Bean没有实现BeanSelfAware标识接口 跳过  
    10.             return bean;  
    11.         }  
    12.         if(AopUtils.isAopProxy(bean)) { //③ 如果当前对象是AOP代理对象,直接注入  
    13.             ((BeanSelfAware) bean).setSelf(bean);  
    14.         } else {  
    15.             //④ 如果当前对象不是AOP代理,则通过context.getBean(beanName)获取代理对象并注入  
    16.             //此种方式不适合解决prototype Bean的代理对象注入  
    17.             ((BeanSelfAware)bean).setSelf(context.getBean(beanName));  
    18.         }  
    19.         return bean;  
    20.     }  
    21.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
    22.         return bean;  
    23.     }  
    24. }  

     

    5、总结

    纵观其上:

    【3.1 通过ThreadLocal暴露Aop代理对象】适合解决所有场景(不管是singleton Bean还是prototype Bean)的AOP代理获取问题(即能解决目标对象的自我调用问题);

     

    【3.2 通过初始化方法在目标对象中注入代理对象】 和【3.4 改进版的InjectBeanSelfProcessor的解决方案】能解决普通(无循环依赖)的AOP代理对象注入问题,而且也能解决【3.3】中提到的循环依赖(应该是singleton之间的循环依赖)造成的目标对象无法注入AOP代理对象问题,但该解决方案不适合解决循环依赖中包含prototype Bean的自我调用问题;

     

    【3.3 通过BeanPostProcessor 在目标对象中注入代理对象】:只能解决 普通(无循环依赖)的 的Bean注入AOP代理,无法解决循环依赖的AOP代理对象注入问题,即无法解决目标对象的自我调用问题。

     

    没有完美的解决方案,只有最适用的解决方案。

    展开全文
  • 介绍: UI客户端框架(最好的jQuery ...(IE8详细测试,估计问题不大,但有些CSS3的效果就不要想了,如圆角,动画什么的) 本框架不适用于需要兼容的Internet Explorer 6、7的开发者或用户。 考虑兼容的IE6和IE7,
  • IMS是未来网络的整体架构,其体系架构增强了对基于IP流的可控和可...实现融合是一个长期的目标,涉及的因素很多。IMS只是在网络和业务层面提供了融合技术的可能性,但还要认真研究其可行性、经济性、复杂性和可管理性。
  • 要求解的问题是:给出一种初始状态和目标状态,用A*算法找到一种最少步骤的移动方法,实现从初始状态到目标状态的转变。 搜索中利用启发式信息,对当前扩展结点根据设定的估价函数值选取离目标最近的结点进行扩展...
  • 问题:目前部分地区酒店的机票预订还进入智能处理阶段,费时费力,效率低下。 项目目标:系统实现后,大大提高旅游局的机票预定服务效率。降低售票服务中的错误发生 率,减少信 息交流的烦琐过程及其带来的开销。...

    一、问题定义

    系统目标与范围说明书

    项目名称:机票预定系统。

    问题:目前部分地区酒店的机票预订还未进入智能处理阶段,费时费力,效率低下。

    项目目标:系统实现后,大大提高旅游局的机票预定服务效率。降低售票服务中的错误发生 率,减少信 息交流的烦琐过程及其带来的开销。

    项目规模:开发成本应该不超过 5 万元。

    初步设想:用学校现有的物力和人力资源开发该系统。

    可行性研究:为了全面分析该系统开发的可能性,建议进行大约 3 周的可行性研究。可行性 研究成本不超过 5000 元。

      随着社会发展的不断进步,民航事业不断壮大,人们生活水平不断提高,乘坐名航 的人也越来越多,随着消费者的不断增多,飞机预订系统在各地预订网点作用也愈显重要。 目前, 我国还有相当一部分地区酒店的机票预订还未进入智能处理阶段, 和发达地区比较工作效率较低。 在计算机技术快速发展的今天, 有必要引进高效的计算机系统来协助机票预订 工作。因此开发一套具有完整的存储,查询,核对,打印机票功能的实时机票预订系统势在 必行。

    机票预定系统应克服存储乘客信息少, 查询效率低下等问题外, 更重要的是其安全性, 可靠性,这关系到航班和乘客的安全及准确,本系统因面向广大机票预定网点,因此要能在 售票网点中普及,则需要开发一个功能全,价格能被顾客所接受的系统。机票预订系统是为了机场工作人员和客户提供订票退票等与机票相关内容和管理的系 统,它具有开放的系统结构,易扩充的,易维护的,具有良好人机界面的优点。它克服了存 储客户信息少,查询效率低等问题,更重要的是其安全性,可靠性,实现航空公司的机票销 售的自动化,为乘客出行提供方便,便于机场人员信息管理,提高了机场人员对机票管理的工作效率。

    二、可行性研究

    1.系统建设目标

    在对系统初步调查的基础上就可以提出项目的开发目标, 即新系统建立后所要求达到的 运行指标,这是系统开发和评价的依据。 由于机票预定系统存在工作量大、 事务繁琐的特点, 预定机票还没有进入智能化处理阶 段,且工作的效率很低。为提高工作效率,减轻机场工作人员的工作负担,决定针对机票预 定开发管理系统软件, 以供航空公司管理人员通过电脑操作进行机票预定管理, 从而使机票 预定管理工作系统化、规范化、自动化,提高整个订票流程的效率,使总体水平上升到一个 新的高度。 并且计算机的存储与快速查询功能大大提高了机票管理的效率, 并且还提高了机票预定的精确度。方便快速的操作,可减少从前的漏洞,又减少因工作的冗余出现的错误,并且操 作非常简单,可减少许多不很必要的人员。

    2.可行性分析

    可行性分析是任何一个大型工程正式投入力量之前必须进行的一项工作。这对于保证资 源的合理利用、 避免浪费是一个十分重要的, 也是项目一旦开始以后能顺利进行的必要保证。当系统的开发目标确定后,就可以从以下三方面对能否实现新系统目标进行可行性分析:

    1)技术可行性

    根据客户提出的系统功能、 性能及实现系统的各项约束条件, 从技术的角度研究实现系 统的可行性

    I、技术分析 当前的科学技术是否支持系统开发的全过程。主要包括一下 4 个方面: ① 采集影响系统性能、可靠性、可维护性方面的信息 ② 论证实现系统功能和性能需要的各种设备、技术、方法和过程 ③ 分析项目开发在技术上担负的风险,及对开发成本的影响等等 ④ 如有可能应研究,现有类似系统的功能、性能,采用的技术、工具、设备、开发 过程中成功和失败的经验、教训,为系统开发作参考。

    II、研究技术可行性的途径主要有一下 4 种: ①系统分析员通过对现实世界的观察和分析建立分析模型 ②评估模型的行为并将它们与现实世界对比 ③论证系统开发方案在技术上的可行性和优缺点。 ④开展其它技术可行性研究和设计活动 III、技术可行性的困难主要体现在以下 4 个方面: ①技术发展块 ②领域知识不熟悉 ③系统目标、功能和性能不确定 ④建立分析模型、仿真随着计算机科学技术的不断进步, 管理信息系统在各个领域上广泛应用。 我国虽处在发 展中,但商品经济的热潮已经不断增长,且人们对于科技的投资正在不断的加大,在现代的 网络与信息技术的高速发展人们对生活质量的要求不断的提高, 及信息技术的依赖, 为了适 应当前的发展形势, 跟上现代科技的发展所以我们有必要为当前数量较多的酒店、 旅行社及 机票预售点设计更为方便快捷的系统,从而更有利于经济的发展。 该机票预定系统是以数据库为后台核心应用、 以服务为目的信息平台, 对资源进行科学 的加工整序和管理维护。

    2)经济可行性

    计算机迅速发展的原因在于, 计算机的应用给社会带来了巨大的经济效益。 基于计算 机系统的成本-效益分析, 给出系统开发的成本论证, 并将估算的成本与预期的利润进行对 比。项目开发成本受项目的特性、规模等因素制约。系统分析员很难直接估算基于计算机系 统的成本和利润,得到完全精确的成本-效益分析结果十分困难。因此非常有必要进行经济可行性研究。

    基于计算机系统的成本: ① 购置并安装软件、硬件及有关设备的费用。 ② 系统开发费用。 ③ 系统安装、运行和维护费用。 ④ 人员培训费用。 在系统分析和设计阶段

    只能得到预算,即估算成本。在系统开发完毕并交付用户运 行后,费用的统计结果就是实际成本。

    经济效益:①系统为用户增加的收入,可以用直接的或统计的方法估算。 ②估算项目的开发成本是否超过预期的利润 ③分析系统开发对其他产品或利润的影响 社会效益: 用定性的方法估算。 该系统的目标是以最低的成本, 最低的投入, 在较短的时间内参阅大量的资料开发出具 有用户登录、存储,查询,核对,打印机票等基本功能,预期系统设计期间所投入的资金较 小,从经济角度考虑,此系统开发可行。

    3)运行可行性

    运行可行性是指所建立的信息系统能否在该企业实现, 在当前的操作环境下能否很好的 进行,即组织内外是否具备接受和使用新系统的条件。 本系统为一个普通的信息管理系统, 所耗费的资源非常的小, 机场的电脑无论是硬件还 是软件都能够满足条件; 而且将来的操作界面简洁易操作, 机场管理人员无需培训即可很快 学会如何进行操作。因此,本系统在运行上是可行的。

    4)法律可行性

    整个系统由于是自行开发,自行使用,在开发过程中没有涉及合同、责任等与法律抵触 的方面。因此,本系统在法律上是可行的。 按上述四方面进行可行性分析、研究后,我们认为该项目是可行的。

    转载于:https://www.cnblogs.com/zhuzh/p/4958696.html

    展开全文
  • 这种问题出现在原理图上,原理图看上去是连上的,由于画线不符和规范,导致表中他们并连上,下面是连线属于不规范的连线: c 超过元器件的断点连线; c 连线的两部分有重复; c 在原理图连线时,应尽量做到: 1 在...
  • 首先,获取待处理图像数据集,进而在计算机平台下搭建并训练神经网络模型,利用得到的训练参数在龙芯派平台下建立优化后的神经网络结构,并对目标图像进行处理识别,最后在用户界面显示目标图像所属类别.本系统利用深度...
  • SIFT源码(python实现

    2018-11-16 19:09:40
    使用包,python源码实现。 SIFT 尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不...
  • 航班降落调度问题可以描述为:机场在某一段时间内有架需要降落航班,每个航班都有一个最早到达时间和最晚到达时间,在这个时间窗口内,航空公司需要选择一个目标时间,并将它作为航班到达时间公布出去,如果比此时间...

    粒子群算法(多维+航班着陆调度+MATLAB实现)

    链接及源码

    MATLAB代码+相关文档PDF

    1. 问题描述

    航班降落调度问题可以描述为:机场在某一段时间内有架需要降落航班,每个航班都有一个最早到达时间和最晚到达时间,在这个时间窗口内,航空公司需要选择一个目标时间,并将它作为航班到达时间公布出去,如果比此时间迟到或早到,会带来额外的费用支出,每个航班都定义了早到每分钟的惩罚和晚到每分钟的惩罚,同时,在两个航班降落之间需要有一段安全时间间隔。问题详细描述见链接文档.

    2. MATLAB代码实现

    2.1. fun.m

    function y = fun(x)
    %函数用于计算粒子适应度值
    %x     ·      input           输入粒子 
    %y           output          粒子适应度值 
    target = [155,258,98,106,123,135,138,140,150,180];%10个航班的target时间,用于计算适应度函数
    c = [10,10,30,30,30,30,30,30,30,30];%10个航班的早到/晚到的惩罚,用于计算适应度函数
    time_span = [0	3	15	15	15	15	15	15	15	15;
    3	0	15	15	15	15	15	15	15	15;
    15	15	0	8	8	8	8	8	8	8;
    15	15	8	0	8	8	8	8	8	8;
    15	15	8	8	0	8	8	8	8	8;
    15	15	8	8	8	0	8	8	8	8;
    15	15	8	8	8	8	0	8	8	8;
    15	15	8	8	8	8	8	0	8	8;
    15	15	8	8	8	8	8	8	0	8;
    15	15	8	8	8	8	8	8	8	0];%计算时间惩罚
    cost = 0.0;
    xx = x';
    for i=1:10
        %disp(x(i))
        cost = (abs(xx(i)-target(i)))*c(i) + cost;
        for j=1:10
            if (abs(xx(i)-xx(j))-time_span(i,j))<0
                cost = Inf;
            end
        end
    end
    y=cost;
    

    2.2. PSO1.m

    %% 清空环境
    clc;clear all;close all;
    %% 设置种群参数
    %   需要自行配置
    SIZEPOP = 100:400:10000;
    ger = 800;                       % 最大迭代次数     
    record = zeros(ger, 25);          % 记录器
    dim = 10;                          % 空间维数
    xlimit_max =[559 744 510	521	555	576	577	573	591	657];    % 设置位置参数限制(矩阵的形式可以多维)
    xlimit_min = [129 195	89	96	110	120	124	126	135	160];
    for x=1:10
       vlimit_max(x)=0.2*(xlimit_max(x)-xlimit_min(x));
       vlimit_min(x)=-vlimit_max(x);
    end
    %for X=1:25
    %sizepop = SIZEPOP(X);                    % 初始种群个数
    sizepop = 6000;          
    % vlimit_max = [50,50,50,50,50,50,50,50,50,50];       % 设置速度限制
    % vlimit_min =[-50,-50,-50,-50,-50,-50,-50,-50,-50,-50];
    c_1 = 0.4;                        % 惯性权重
    c_2 = 0.5;                        % 自我学习因子
    c_3 = 2;                        % 群体学习因子 
    
    %% 生成初始种群
    %  首先随机生成初始种群位置
    %  然后随机生成初始种群速度
    %  然后初始化个体历史最佳位置,以及个体历史最佳适应度
    %  然后初始化群体历史最佳位置,以及群体历史最佳适应度
    for i=1:dim
       for j=1:sizepop
           pop_x(i,j) = xlimit_min(i)+(xlimit_max(i) - xlimit_min(i))*rand;
           pop_v(i,j) = vlimit_min(i)+(vlimit_max(i) - vlimit_min(i))*rand;  % 初始种群的速度
    
       end
    end    
    gbest = pop_x;                                % 每个个体的历史最佳位置
    for k=1:sizepop
       fitness_gbest(k) = fun(pop_x(:,k));                   % 每个个体的历史最佳适应度
    end
    zbest = pop_x(:,1);                           % 种群的历史最佳位置
    fitness_zbest = fitness_gbest(1);             % 种群的历史最佳适应度
    for j=1:sizepop
       if fitness_gbest(j) < fitness_zbest       % 如果求最小值,则为<; 如果求最大值,则为>; 
           zbest = pop_x(:,j);
           fitness_zbest=fitness_gbest(j);
       end
    end
    
    
    %% 粒子群迭代
    %    更新速度并对速度进行边界处理    
    %    更新位置并对位置进行边界处理
    %    进行自适应变异
    %    计算新种群各个个体位置的适应度
    %    新适应度与个体历史最佳适应度做比较
    %    个体历史最佳适应度与种群历史最佳适应度做比较
    %    再次循环或结束
    
    iter = 1;                        %迭代次数
    
    while iter <= ger
       for j=1:sizepop
           %    更新速度并对速度进行边界处理 
           pop_v(:,j)= c_1 * pop_v(:,j) + c_2*rand*(gbest(:,j)-pop_x(:,j))+c_3*rand*(zbest-pop_x(:,j));% 速度更新
           for i=1:dim
               if  pop_v(i,j) > vlimit_max(i)
                   pop_v(i,j) = vlimit_max(i);
               end
               if  pop_v(i,j) < vlimit_min(i)
                   pop_v(i,j) = vlimit_min(i);
               end
           end
    
           %    更新位置并对位置进行边界处理
           pop_x(:,j) = pop_x(:,j) + pop_v(:,j);% 位置更新
           for i=1:dim
               if  pop_x(i,j) > xlimit_max(i)
                   pop_x(i,j) = xlimit_max(i);
               end
               if  pop_x(i,j) < xlimit_min(i)
                   pop_x(i,j) = xlimit_min(i);
               end
           end
    
              %进行自适应变异
           if rand > 0.85
               i=ceil(dim*rand);
               pop_x(i,j)=xlimit_min(i) + (xlimit_max(i) - xlimit_min(i)) * rand;
           end
    
           %    计算新种群各个个体位置的适应度
    
           fitness_pop(j) = fun(pop_x(:,j));                      % 当前个体的适应度
    
    
           %    新适应度与个体历史最佳适应度做比较
           if fitness_pop(j) < fitness_gbest(j)       % 如果求最小值,则为<; 如果求最大值,则为>; 
               gbest(:,j) = pop_x(:,j);               % 更新个体历史最佳位置            
               fitness_gbest(j) = fitness_pop(j);     % 更新个体历史最佳适应度
           end   
    
           %    个体历史最佳适应度与种群历史最佳适应度做比较
           if fitness_gbest(j) < fitness_zbest        % 如果求最小值,则为<; 如果求最大值,则为>; 
               zbest = gbest(:,j);                    % 更新群体历史最佳位置  
               fitness_zbest=fitness_gbest(j);        % 更新群体历史最佳适应度  
           end    
       end
    
       record(iter,1) = fitness_zbest;%最大值记录
    
       iter = iter+1;
    
    end
    %end
    %% 迭代结果输出
    disp(zbest);
    plot(record);title('收敛过程')
    disp(['最优值:',num2str(fitness_zbest)]);
    
    展开全文
  • 现有风电和光伏分布式电源(DG)规划模型均配电网中的主变、馈线N-1约束,所得配置方案未必满足安全性要求。为解决该问题,提出一种考虑N-1安全的多目标DG选址定容规划模型。基于安全距离模型,介绍配电网N-1...
  • 针对现有动态火力分配模型考虑不确定因素复杂约束的问题,引入不确定规划理论,建立了基于模糊机会约束双层规划的动态火力分配模型.首先,以最大化效费比和尽早拦截分别...
  • 但附带的问题是:在驱动信号停止后,由于谐振的原因,发射头还会持续较长时间发射,直至能量在变压器的次级线包直流电阻上消耗完,这样就导致在近距离测量时,回波都到了,余波还结束,导致测量失败。所以设计了一...
  •  正如作者所说——“我的书目标很简单,那就是填补这个空白,架起学院教科书与通常针对SQL Server所写的,纯粹面向实践的书之间的桥梁”。翻译的过程中,译者感到此言不虚:作者从数据库的基本概念到数据库建模,从...
  •  正如作者所说——“我的书目标很简单,那就是填补这个空白,架起学院教科书与通常针对SQL Server所写的,纯粹面向实践的书之间的桥梁”。翻译的过程中,译者感到此言不虚:作者从数据库的基本概念到数据库建模,从...
  • 尽管SMPS(开关电源)本身能防止永久性短路,但在遇到瞬时过载时有时会出问题。瞬时过载并非短路,但却会使电源...由于在VOUT远达到其目标值时,反馈电流尚未建立,所以启动序列就是短路。标称输出电流I1对应于负载
  • 用面向对象方法和面向对象程序设计语言,实现满足下述要求的一个高层建筑电梯活动 仿真程序。 问题域概述 某国际展览中心共 40 层,设有载客电梯10 部(用E0~E9 标识)。 限定条件 (1) 电梯的运行规则是: E0、E1...
  • 针对这一问题,本文在分析现有嵌入式安全操作系统构建原理技术的基础上,提出了VxWorks安全内核,实现了基于多策略的强制访问控制等安全机制。测试表明,该安全内核不仅增强了VxWorks系统的安全性,而且对其实时性...
  • 中国的市场经济体制改革将实现产权清晰、权责明确作为重要目标。在当前的改革进程中,人防工程的产权归属处于一种混乱状态,导致谁出资、谁受益这一政策并完全落实。文章将已开发利用的民用建筑人防工程作为研究...
  • 三、研究的目标、内容和拟解决的关键问题 利用在线图书销售系统帮助没有任何网络知识的商家建立一个网上图书商城,可以实现用户的注册、商品的展示、在线定购、在线支付等嗲子商务功能,使客户能享受到网上购物的...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 348
精华内容 139
关键字:

未实现目标及问题