面向企业应用的Android开发从入门到精通

安卓开发经验总结

开发环境搭建

现在主流的开发环境就两种,ADT和Android Studio。以前因为使用Eclipse的缘故,总是觉得Android Studio不好。这也是实情,很多习惯没法改变。但自从看到Google不再维护ADT后,就下决心更改开发工具。使用一段时间,发现其实Android Studio还是挺好用的。这也说明一个问题,IT人员有时要敢于突破,不要在老的经验上洋洋自得。

Android Studio的环境搭建文章多的是,就不一一说明了,只是提到其中一些该注意的点。

1、  Java SDK需要1.7以上

2、  Android Studio的官网是无法直接访问的,谁叫他姓Google呢。http://www.android-studio.org/中有下载,但不是最新版本,目前最新为1.5.0.4,自己找代理下载吧。

3、  Android SDK安装和更新都需要设置代理。在『Android SDK Manager - Settings』窗口中,在「HTTPProxy Server」和「HTTP Proxy Port」输入框内填入 mirrors.neusoft.edu.cn 80,并且选中「Force https://… sources to be fetched using http://…」复选框。

使用常识

1、Android Studio和ADT的对比

Android Studio

ADT

Project

Workspace

Module

Project

2、Android Virtual Device(AVD)需要注意事项:

1)AVD设置时需要进入高级设置,修改RAM、VM heap、Internal Storage和SD card大小,避免过大,造成没有内存分配,这样启动不起来。

2)AVD需要安装HAXM(Intel X86 Emulator Accelerator, 在Android SDK列表的Extras中)。如果本机的硬件加速没有打开,还需要重启机器,进入Bios去打开硬件加速。每台机器的Bios进入有细微差别,搜索一下就知道怎么改了,无非是F1、F2、DEL、F8、F10等这些功能键。

3、使用真机开发的话,android的版本最好在4.2.2以上,为什么呢。不知道,反正我用4.1.2集成信鸽推送时,窗口栏总是不显示推送信息,试了各种手段,都不显示,但实际上是隐藏着的。

开始Hello World

环境搭建好后,启动AndroidStudio,就可以开发Android应用了。Android是以JAVA为基础衍生的,那开发人员自然要学习下JAVA了。

开始界面

以上功能都可以根据需要使用,但导入ADT工程不是很好用,导入进来,不能直接使用,还要调整半天,不推荐使用,不如自己创建一个新工程来的清晰。

新建工程时,你可以根据需要创建一个默认的Activity,也可以不创建,进入后慢慢增加。不同版本的Android Build-tools自动创建的Activity继承的基类不一样,这也是与时俱进吧,呵呵。

工程管理界面

    通过切换视图,可以看到不同的工程目录界面。方便个人的开发习惯。从ADT切换过来,开始还是习惯看Project方式,用用后,感觉Android方式也挺不错。

mipmap和drawable

新的Android体系中, mipmap和drawable同时存在,功能都是用于存放图片资源。但mipmap只存放图标资源,并不是别人说的mipmap替换drawable。下面是google的官方描述:

drawable/

For bitmap files (PNG, JPEG, or GIF), 9-Patch image files, andXML files that describe Drawable shapes or Drawable objects that containmultiple states (normal, pressed, or focused). See the Drawable resource type.

mipmap/

For app launcher icons. The Android system retains the resourcesin this folder (and density-specific folders such as mipmap-xxxhdpi) regardlessof the screen resolution of the device where your app is installed. Thisbehavior allows launcher apps to pick the best resolution icon for your app todisplay on the home screen. For more information about using the mipmapfolders, see Managing Launcher Icons as mipmap Resources.

常用的功能开发

一个应用,开始就是欢迎页面。如果首次登陆,进入宣传页面;如果不是则进入登陆页(如果已经登陆成功过,则自动进入主页)。当然,如果应用不需要先登录,则可以进入主页。以后就是各个Activity之间的相关跳转,参数传递。这个就根据需要来实现了。

当然还有个更重要的功能,就是接收消息通知,并进行处理。

         在开发中,我喜欢使用WebView来作为展示的主体。这样的话,业务本身的调整就不太容易影响应用本身,不需要不停的升级来解决业务展示的问题。当然,WebView和Activity之间必然存在参数的传递,这也是要重点解决的。好在有万能的百度,这些都不是问题。

制作欢迎页面

这是应用打开的第一个页面,一般是公司的Logo或产品名称。一般停顿三秒钟后,就会跳转,所以通常都命名为SplashActivity。

页面完成自己的初始化后,第一步就是要判断是否首次登陆。这里会用到Android的本地存储功能,本人使用的是SharedPreferences。

// 读取SharedPreferences中需要的数据
// 使用SharedPreferences来记录程序的使用次数
SharedPreferencespreferences = getSharedPreferences(
        SHAREDPREFERENCES_NAME,MODE_PRIVATE);

// 取得相应的值,如果没有该值,说明还未写入,用true作为默认值
isFirstIn=preferences.getBoolean("isFirstIn",true);

// 判断程序与第几次运行,如果是第一次运行则跳转到引导界面,否则跳转到主界面
if (!isFirstIn) {
    // 使用Handler的postDelayed方法,3秒后执行跳转到MainActivity
    //获取用户id
    String server_nonce = (String) GlobalData.getUserId();
    if (server_nonce.isEmpty()) {
        mHandler.sendEmptyMessageDelayed(GO_LOGIN, SPLASH_DELAY_MILLIS);
    } else {
        mHandler.sendEmptyMessageDelayed(GO_MAIN, SPLASH_DELAY_MILLIS);
    }

} else {
    mHandler.sendEmptyMessageDelayed(GO_GUIDE, SPLASH_DELAY_MILLIS);
}

 

在宣传页面执行完后,要将isFisrtIn置为true,否则每次进入都要进入宣传页面了。

其中的mHandler用于延时执行相应的跳转:

/**
 * Handler:跳转到不同界面
 */
private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case GO_LOGIN:
                goLogin();
                break;
            case GO_GUIDE:
                goGuide();
                break;
            case GO_MAIN:
                goMain();
                break;
        }
        super.handleMessage(msg);
    }
};

跳转的代码很简单。

Intent intent = new Intent(SplashActivity.this, MainActivity.class);
SplashActivity.this.startActivity(intent);
SplashActivity.this.finish();

如果要传递参数,可以设置intent的附属属性,如下:

Bundle bundle = new Bundle();
bundle.putString("username","abc");
bundle.putBoolean("isLogin",true);
intent.putExtras(bundle);

也可以在洗头中设置全局变量,通过全局变量进行传递。对于用户id,所有Activity都要使用,这种数据使用全局变量更合适。

/**
 * Created by Administrator on 2015/11/20.
 */
public class GlobalData {

    private static String username = "";

    private static String userId = "";

    public static String getUserId() {
        return userId;
    }

    public static void setUserId(String userId) {
        GlobalData.userId = userId;
    }

    public static String getUsername() {
        return username;
    }

    public static void setUsername(String username) {
        GlobalData.username = username;
    }

在需要的地方进行读取和设置。

GlobalData.setUserId(userId);
GlobalData.setUsername(mUsername);

 

//获取用户id
server_nonce = (String) GlobalData.getUserId();

效果如下:

制作宣传页

宣传页的作用就是通过几张图片或文字,把当前应用的功能或使用方式做个宣传。

宣传页使用的主要技术就是PagerAdapterPagerAdapter主要是viewpager的适配器,而viewPager则也是在android.support.v4扩展包中新添加的一个强大的控件,可以实现控件的滑动效果,比如咱们在软件中常见的广告栏的滑动效果,用viewPager就可以实现。以下代码也是百度提供,直接贴出来,供参考:)。

先建立GuideActivity,实现宣传页面的布局和Adapter的初始化。

public class GuideActivity extends Activity implements OnPageChangeListener {

    private ViewPager vp;
    private ViewPagerAdapter vpAdapter;
    private List<View> views;

    // 底部小点图片
    private ImageView[] dots;

    // 记录当前选中位置
    private int currentIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.guide_layout);

        // 初始化页面
        initViews();

        // 初始化底部小点
        initDots();
    }

    private void initViews() {
        LayoutInflater inflater = LayoutInflater.from(this);

        views = new ArrayList<View>();
        // 初始化引导图片列表
        views.add(inflater.inflate(R.layout.what_new_01_layout, null));
        views.add(inflater.inflate(R.layout.what_new_02_layout, null));
        views.add(inflater.inflate(R.layout.what_new_03_layout, null));
        views.add(inflater.inflate(R.layout.what_new_04_layout, null));

        // 初始化Adapter
        vpAdapter = new ViewPagerAdapter(views, this);

        vp = (ViewPager) findViewById(R.id.viewpager);
        vp.setAdapter(vpAdapter);
        // 绑定回调
        vp.setOnPageChangeListener(this);
    }

    private void initDots() {
        LinearLayout ll = (LinearLayout) findViewById(R.id.ll);

        dots = new ImageView[views.size()];

        // 循环取得小点图片
        for (int i = 0; i < views.size(); i++) {
            dots[i] = (ImageView) ll.getChildAt(i);
            dots[i].setEnabled(true);// 都设为灰色
        }

        currentIndex = 0;
        dots[currentIndex].setEnabled(false);// 设置为白色,即选中状态
    }

    private void setCurrentDot(int position) {
        if (position < 0 || position > views.size() - 1
                || currentIndex == position) {
            return;
        }

        dots[position].setEnabled(false);
        dots[currentIndex].setEnabled(true);

        currentIndex = position;
    }

    // 当滑动状态改变时调用
    @Override
    public void onPageScrollStateChanged(int arg0) {
    }

    // 当当前页面被滑动时调用
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    }

    // 当新的页面被选中时调用
    @Override
    public void onPageSelected(int arg0) {
        // 设置底部小点选中状态
        setCurrentDot(arg0);
    }

 

<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
    tools:context=".GuideActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="24.0dp"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/dot" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/dot" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/dot" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            android:padding="15.0dip"
            android:src="@drawable/dot" />
    </LinearLayout>

</RelativeLayout>

再建立PagerAdapter,实现页面页面切换、完成初始化设置和进入登陆页。实现PagerAdapter,就需要完成相关方法的重载。

public class ViewPagerAdapter extends PagerAdapter {

    private static final String SHAREDPREFERENCES_NAME = "first_pref";
    // 界面列表
    private List<View> views;
    private Activity activity;

    public ViewPagerAdapter(List<View> views, Activity activity) {
        this.views = views;
        this.activity = activity;
    }

    // 销毁arg1位置的界面
    @Override
    public void destroyItem(View arg0, int arg1, Object arg2) {
        ((ViewPager) arg0).removeView(views.get(arg1));
    }

    @Override
    public void finishUpdate(View arg0) {
    }

    // 获得当前界面数
    @Override
    public int getCount() {
        if (views != null) {
            return views.size();
        }
        return 0;
    }

    // 初始化arg1位置的界面
    @Override
    public Object instantiateItem(View arg0, int arg1) {
        ((ViewPager) arg0).addView(views.get(arg1), 0);
        if (arg1 == views.size() - 1) {
            Button btnEnter = (Button) arg0
                    .findViewById(R.id.btnEnter);
            btnEnter.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // 设置已经引导
                    setGuided();
                    goHome();

                }

            });
        }
        return views.get(arg1);
    }

    private void goHome() {
        // 跳转到登陆页,能够进入宣传页,证明肯定没进行过登陆,不用考虑是否已登录过。
        Intent intent = new Intent(activity, LoginActivity.class);
        activity.startActivity(intent);
        activity.finish();
    }

    /**
     * method desc:设置已经引导过了,下次启动不用再次引导
     */
    private void setGuided() {
        SharedPreferences preferences = activity.getSharedPreferences(
                SHAREDPREFERENCES_NAME, Context.MODE_PRIVATE);
        Editor editor = preferences.edit();
        // 存入数据
        editor.putBoolean("isFirstIn", false);
        // 提交修改
        editor.commit();
    }

    // 判断是否由对象生成界面
    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return (arg0 == arg1);
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void startUpdate(View arg0) {
    }

}

效果如下:

登陆页面

登陆页面通常会包括两部分内容:1、输入用户名称和密码;2、设置服务器信息。更多的互联网应用还会提供注册页面,让用户自己填写信息,短信确认。当然,这些都要根据自己的实际情况去实现了。我这里实现的是一个非常常规的企业办公软件,就不需要这么复杂了。

好了,开工。

Android Studio本身就携带Login Activity模板,基于此模板,增加自己的登陆逻辑即可。

我在该基础上增加的有:

1、  是否记住密码

2、  调用自己的后台登陆接口实现登陆。

3、  登陆成功后,保存用户名称、密码和是否记住密码到本地缓存,并将用户id写入全局变量,供其它Activity使用。

效果如下:

初始化时,读取本地缓存的用户数据,对相关的输入框进行初始化:

private void init() {
    // 读取SharedPreferences中需要的数据
    // 使用SharedPreferences来记录登陆用户参数
    SharedPreferences preferences = getSharedPreferences(
            LOGIN_PARAMETER, MODE_PRIVATE);

    // 初始化是否记住密码
    boolean rememberMe = preferences.getBoolean(REMEMBER_ME, false);
    if (rememberMe) {
        mRememberMeView.setChecked(true);
    }
    // 初始化用户名
    String username = preferences.getString(USER_NAME, "");
    if (!username.isEmpty()) {
        mUsernameView.setText(username);
    }
    // 初始化密码
    String password = preferences.getString(PASSWORD, "");
    if (!password.isEmpty()) {
        mPasswordView.setText(password);
    }
    // 初始化服务地址
    String serverAddress = preferences.getString(SERVER_ADDRESS, "");
    if (!serverAddress.isEmpty()) {
        mServerAddressView.setText(serverAddress);
    }

}

 

点击设置按钮,可以查看服务地址:

mSettingView = (TextView) findViewById(R.id.btnSetting);
mSettingView.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mServerAddressLayout.getVisibility() == View.VISIBLE) {
            mServerAddressLayout.setVisibility(View.INVISIBLE);
        } else {
            mServerAddressLayout.setVisibility(View.VISIBLE);
        }
        mServerAddressLayout.refreshDrawableState();
    }
});

 

点击登陆,执行登陆逻辑,先检查关键信息是否输入,再调用后台接口,实现用户密码验证。这里的关键点就是需要引入HttpClient包,实现HTTP请求和响应。验证通过,则将用户数据写入本地缓存,将用户id写入全局变量:

@Override
protected Boolean doInBackground(Void... params) {
    String url = "";
    if (mServerAddress.startsWith("http://") || mServerAddress.startsWith("https://")) {
        url = mServerAddress + "/authenticate.m";
    } else {
        url = "http://" + mServerAddress + "/authenticate.m";
    }

    HttpPost httpPost = new HttpPost(url);
    List<NameValuePair> httpparams = new ArrayList<NameValuePair>();
    httpparams.add(new BasicNameValuePair("userid", mUsername));
    httpparams.add(new BasicNameValuePair("password", mPassword));
    try {
        httpPost.setEntity(new UrlEncodedFormEntity(httpparams, HTTP.UTF_8));
        HttpResponse httpResponse = new DefaultHttpClient().execute(httpPost);
        if (httpResponse.getStatusLine().getStatusCode() == 200) {
            String result = EntityUtils.toString(httpResponse
                    .getEntity());
            JSONObject resultJson = new JSONObject(result);
            String userId = resultJson.getJSONArray("body").getJSONObject(0).getString("userId");

            GlobalData.setUserId(userId);
            GlobalData.setUsername(mUsername);

            SharedPreferences preferences = getSharedPreferences(
                    LOGIN_PARAMETER, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = preferences.edit();
            // 存入数据
            editor.putString(SERVER_ADDRESS, mServerAddress);
            // 存入数据
            editor.putString(USER_NAME, mUsername);

            if (mRememberMe) {
                // 存入数据
                editor.putBoolean(REMEMBER_ME, mRememberMe);
                // 存入数据
                editor.putString(PASSWORD, mPassword);
            } else {
                // 存入数据
                editor.putBoolean(REMEMBER_ME, false);
                // 存入数据
                editor.putString(PASSWORD, "");
            }

            // 提交修改
            editor.commit();
        }
    } catch (Exception e) {
        return false;
    }

    return true;
}

 

跳转到主页面。

@Override
protected void onPostExecute(final Boolean success) {
    mAuthTask = null;
    showProgress(false);

    if (success) {
        Intent intent = new Intent(LoginActivity.this, MainActivity.class);// 从登陆页跳到主页
        startActivity(intent);
        LoginActivity.this.finish();
    } else {
        mPasswordView.setError(getString(R.string.error_incorrect_password));
        mPasswordView.requestFocus();
    }
}

登陆页开发完成。虽然生成的代码有很多逻辑没理清楚,但不影响使用。

主页

主页是展示业务的地方。这里只提供一个WebView,实现业务网站的嵌套。唯一要做的就是把页面需要的初始化参数传入。

参数主要通过Cookie进行传入。

对WebView,还要设置一些参数,以支持JS、支持附件上传和下载。下面对这些关键点进行一一说明。

WebView属性设置:

//WebView
WebView browser = (WebView) findViewById(R.id.webView);

//设置可自由缩放网页
browser.getSettings().setSupportZoom(true);
browser.getSettings().setBuiltInZoomControls(true);

//设置支持JS
browser.getSettings().setJavaScriptEnabled(true);

// 如果页面中链接,如果希望点击链接继续在当前browser中响应,
// 而不是新开Android的系统browser中响应该链接,必须覆盖webview的WebViewClient对象
browser.setWebViewClient(new WebViewClient() {
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        //  重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边
        view.loadUrl(url);
        return true;
    }
});

//实现页面上传附件功能
browser.setWebChromeClient(new WebChromeClient() {
    //The undocumented magic method override
    //Eclipse will swear at you if you try to put @Override here
    // For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {

        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);

    }

    // For Android 3.0+
    public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        MainActivity.this.startActivityForResult(
                Intent.createChooser(i, "File Browser"),
                FILECHOOSER_RESULTCODE);
    }

    //For Android 4.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);

    }

});

//实现页面下载附件功能,基于浏览器实现
browser.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype,
                                long contentLength) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }
});

同时还要创建相关的方法以支持属性设置:

@Override
protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
    if (requestCode == FILECHOOSER_RESULTCODE) {
        if (null == mUploadMessage) return;
        Uri result = intent == null || resultCode != RESULT_OK ? null
                : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;
    }
}

 

Cookie同步,通常就是同步用户id,在打开相应Url的时候调用即可:

    synCookies(getBaseContext(), url, "userId=" + userId);
    browser.loadUrl(url);
 

 

/**
 * 同步一下cookie
 */
public static void synCookies(Context context, String url, String value) {
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    cookieManager.setCookie(url, value);//cookies是在HttpClient中获得的cookie
    Log.d("cookie", cookieManager.getCookie(url));
}

 

如果需要在每次打开页面的时候都重新刷新一下WebView,需要增加以下代码:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);// 必须要调用这句
    openUrl();
}

 效果如下:

 

Android还有一个更强大的功能就是能够实现WebView中的JS调用JAVA功能,JAVA也可以调用JS方法,只是配置有点复杂,目前没感觉特别有用,没有去深究,有兴趣的就去问百度了,呵呵。

消息通知

世面上有很多免费和收费的消息推送服务,接触到的有极光推送、个推、百度推送、腾讯信鸽推送。极光和个推都是有收费版的,这样的不太放心,于是在百度和腾讯中选。发现腾讯有个好的就是可以按别名推送,刚好满足使用账号推送的需求,于是选择了他。

集成腾讯信鸽推送其实很简单,按照他的Demo或文档描述配置即可,这里只强调一下关键的用法,比如参数传递。

服务端只要引入他的XingeApp.jar,然后再需要的地方初始化,并发送消息即可。其中的accessId和secret是在注册应用时自动生成的唯一信息。可以进入信鸽推送管理平台获取。

int accessId = 21001*****;

String secret = "**************";

XingeApp xinge = new XingeApp(accessId, secret);

。。。。。。

Message message = new Message();

message.setExpireTime(86400);

message.setTitle(attention.getTitle());

message.setContent(content);

message.setType(Message.TYPE_NOTIFICATION);

 

//传递自定义参数

Map<String, Object> mapValue = new HashMap<String,Object>();

mapValue.put("relativeId",attention.getRelativeId());

mapValue.put("messageType",attention.getMessageType);

message.setCustom(mapValue);

 

ClickAction action = new ClickAction();

action.setActionType(ClickAction.TYPE_ACTIVITY);

action.setActivity("net.qiangqi.oa.MessageActivity");

message.setAction(action);

org.json.JSONObject ret = xinge.pushAccountList(0, userIds, message);

服务端集成就这么简单。

 

Android应用集成也很简单,参考Demo即可。但Demo没有涉及参数的传递,这里着重描述一下。

信鸽客户端是要在Activity的onStart或onRestart才能截获。开始的时候,我把截获的代码放在onCreate中,死活也得不到参数,也是在度娘的帮助下,才发现这个问题。信鸽的Demo应该要补充下这个信息才好。

1、  在onCreate中对信鸽客户端进行注册。这里也要注意,不要每次都进行注册,最好记录一下注册的状态,如果已经注册,则不要重复发起注册,一方面浪费时间,另一方面会造成现有消息因为注册而被销毁。

2、  在onStart中进行消息参数截获,并处理。其中的click.getCustomContent()中的值就是服务器端message.setCustom(mapValue)中设置的

@Override
protected void onStart() {
    super.onStart();
    // 读取SharedPreferences中需要的数据
    // 使用SharedPreferences来记录登陆用户参数
    SharedPreferences preferences = getSharedPreferences(
            LOGIN_PARAMETER, MODE_PRIVATE);

    // 获取服务器地址
    String mServerAddress = preferences.getString(SERVER_ADDRESS, "");
    String url = "http://" + mServerAddress+ "/index.html";
    //获取用户id
    userId = (String) GlobalData.getUserId();
    //WebView
    WebView browser = (WebView) findViewById(R.id.webView);
    boolean detailed = false;
    synCookies(getBaseContext(), url, "userId=" + ");
    //获取推送消息附属信息
    XGPushClickedResult click = XGPushManager.onActivityStarted(this);
   if (click != null) {
       String customContent = click.getCustomContent();
       // 获取自定义key-value
       if (customContent != null && customContent.length() != 0) {
           try {
               JSONObject json = new JSONObject(customContent);
               if (json.get("messageType") != null && json.get("relativeId") != null) {
                   indexUrl = indexUrl
                                + "?messageType=" + json.getString("messageType")
                                + "&relateId=" + json.getString("relativeId");
                   browser.loadUrl(indexUrl);
                   detailed = true;
               }

          } catch (JSONException e) {
               e.printStackTrace();
          }
     }
}
if (!detailed) {
        Intent intent = new Intent(MessageActivity.this, MainActivity.class);// 从欢迎页跳到登陆页
        startActivity(intent);
        MessageActivity.this.finish();
}
}

大功告成。

这里有个需要注意的地方是:信鸽推送应该不支持低版本的Anroid。开始我在三星Notes 2上开发测试,看到消息推送到手机了,但在窗口栏中死活不显示,曾经偶尔看到闪了这么一下,于是各种怀疑,各种假设,都没有成功。最后换了个手机,消息马上显示出来了。这个教训是用了几天时间发现的,说起来有点丢人,大家千万注意:)。

总结

到此为止,一个有点样子的Android应用就开发出来了,没有想象的这么难。对于企业级的APP,内嵌网页我觉得是比较合适的,因为业务在不停的调整,不能因为这个去不停的升级客户端,而且也没法让一个客户端去支持多个企业。

做完了客户端,再写写这个总结,还是颇有收获,希望对大家有所帮助。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值