标签归档:Android

Android:通过Url打开App

Android支持通过Url打开App,比如下面的Url
scheme://host/datastring
要打开这样的Url,首先在配置文件AndroidManifest.xml里使用<data>添加一种App打开的格式,代码如下

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
  package=”com.sheng00.customuridemo”
  android:versionCode=”1″
  android:versionName=”1.0″ >
  <uses-sdk
    android:minSdkVersion=”9″
    android:targetSdkVersion=”17″ />
  <application
    android:allowBackup=”true”
    android:icon=”@drawable/ic_launcher”
    android:label=”@string/app_name”
    android:theme=”@style/AppTheme” >
    <activity
      android:name=”com.sheng00.customuridemo.MainActivity”
      android:label=”@string/app_name” >
      <intent-filter>
        <action android:name=”android.intent.action.MAIN” />
        <category android:name=”android.intent.category.LAUNCHER” />
      </intent-filter>
      <!– Open links like scheme://host/?… –>
      <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=”scheme” android:host=”host” />
      </intent-filter>
    </activity>
  </application>
</manifest>

注意,第二个<intent-filter>中的data绑定了url 在页面中出现scheme://host/类似这样的链接,点击就可以直接打开app app中处理链接地址代码如下

package com.sheng00.customuridemo;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }
  @Override
  protected void onResume() {
    super.onResume();
    Intent intent = getIntent();
    if (intent != null) {
      String action = intent.getAction();
      String dataString = intent.getDataString();
      if(dataString!=null){
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.append("n" + dataString);
      }
    }
  }
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }
}

运行效果
运行效果

源代码:https://github.com/shengoo/myandroidcode/tree/master/CustomUriDemo

Javascript检测终端浏览器是android或ipad、iphone

有些时候会需要判断页面是在哪种移动终端上运行的
navigator.appVersion:
<script>document.write(navigator.appVersion);</script>
<br/>
Device type:
<script>if((/android/gi).test(navigator.appVersion))
document.write("android");
if((/iphone|ipad/gi).test(navigator.appVersion))
document.write("IOS");
</script>
<br/>

 

提示:你可以先修改部分代码再运行。

ps:本文只打印出了是不是android或ios,其他的没有打出来

Customized SeekBarPreference

Android没有提供SeekBarPreference,所以只有自己写一个了。。

SeekBarPreference.java

package com.sheng00.BatteryStatus;
import com.sheng00.BattaryStatus.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {
    private final String TAG = getClass().getName();
    private static final String ANDROIDNS="http://schemas.android.com/apk/res/android";
    private static final String SHENG00NS="http://sheng00.com";
    private static final int DEFAULT_VALUE = 50;
    private int mMaxValue      = 100;
    private int mMinValue      = 0;
    private int mInterval      = 1;
    private int mCurrentValue;
    private String mUnitsLeft  = "";
    private String mUnitsRight = "";
    private SeekBar mSeekBar;
    private TextView mStatusText;
    public SeekBarPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPreference(context, attrs);
    }
    public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initPreference(context, attrs);
    }
    private void initPreference(Context context, AttributeSet attrs) {
        setValuesFromXml(attrs);
        mSeekBar = new SeekBar(context, attrs);
        mSeekBar.setOnSeekBarChangeListener(this);
        mSeekBar.setMax(mMaxValue - mMinValue);
    }
    private void setValuesFromXml(AttributeSet attrs) {
        mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", 100);
        mMinValue = attrs.getAttributeIntValue(SHENG00NS, "min", 0);
        mUnitsLeft = getAttributeStringValue(attrs, SHENG00NS, "unitsLeft", "");
        String units = getAttributeStringValue(attrs, SHENG00NS, "units", "");
        mUnitsRight = getAttributeStringValue(attrs, SHENG00NS, "unitsRight", units);
        try {
            String newInterval = attrs.getAttributeValue(SHENG00NS, "interval");
            if(newInterval != null)
                mInterval = Integer.parseInt(newInterval);
        }
        catch(Exception e) {
            Log.e(TAG, "Invalid interval value", e);
        }
    }
    private String getAttributeStringValue(AttributeSet attrs, String namespace, String name, String defaultValue) {
        String value = attrs.getAttributeValue(namespace, name);
        if(value == null)
            value = defaultValue;
        return value;
    }
    @Override
    protected View onCreateView(ViewGroup parent){
        RelativeLayout layout =  null;
        try {
            LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            layout = (RelativeLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
        }
        catch(Exception e)
        {
            Log.e(TAG, "Error creating seek bar preference", e);
        }
        return layout;
    }
    @Override
    public void onBindView(View view) {
        super.onBindView(view);
        try
        {
            // move our seekbar to the new view we've been given
            ViewParent oldContainer = mSeekBar.getParent();
            ViewGroup newContainer = (ViewGroup) view.findViewById(R.id.seekBarPrefBarContainer);
            if (oldContainer != newContainer) {
                // remove the seekbar from the old view
                if (oldContainer != null) {
                    ((ViewGroup) oldContainer).removeView(mSeekBar);
                }
                // remove the existing seekbar (there may not be one) and add ours
                newContainer.removeAllViews();
                newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
        }
        catch(Exception ex) {
            Log.e(TAG, "Error binding view: " + ex.toString());
        }
        updateView(view);
    }
    /**
     * Update a SeekBarPreference view with our current state
     * @param view
     */
    protected void updateView(View view) {
        try {
            RelativeLayout layout = (RelativeLayout)view;
            mStatusText = (TextView)layout.findViewById(R.id.seekBarPrefValue);
            mStatusText.setText(String.valueOf(mCurrentValue));
            mStatusText.setMinimumWidth(30);
            mSeekBar.setProgress(mCurrentValue - mMinValue);
            mSeekBar.setEnabled(this.isEnabled());
            TextView unitsRight = (TextView)layout.findViewById(R.id.seekBarPrefUnitsRight);
            unitsRight.setText(mUnitsRight);
            TextView unitsLeft = (TextView)layout.findViewById(R.id.seekBarPrefUnitsLeft);
            unitsLeft.setText(mUnitsLeft);
        }
        catch(Exception e) {
            Log.e(TAG, "Error updating seek bar preference", e);
        }
    }
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        int newValue = progress + mMinValue;
        if(newValue > mMaxValue)
            newValue = mMaxValue;
        else if(newValue < mMinValue)
            newValue = mMinValue;
        else if(mInterval != 1 && newValue % mInterval != 0)
            newValue = Math.round(((float)newValue)/mInterval)*mInterval;
        // change rejected, revert to the previous value
        if(!callChangeListener(newValue)){
            seekBar.setProgress(mCurrentValue - mMinValue);
            return;
        }
        // change accepted, store it
        mCurrentValue = newValue;
        if (mStatusText != null) {
            mStatusText.setText(String.valueOf(newValue));
        }
        persistInt(newValue);
    }
    public void onStartTrackingTouch(SeekBar seekBar) {}
    public void onStopTrackingTouch(SeekBar seekBar) {
        notifyChanged();
    }
    @Override
    protected Object onGetDefaultValue(TypedArray ta, int index){
        int defaultValue = ta.getInt(index, DEFAULT_VALUE);
        return defaultValue;
    }
    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        if(restoreValue) {
            mCurrentValue = getPersistedInt(mCurrentValue);
        }
        else {
            int temp = 0;
            try {
                temp = (Integer)defaultValue;
            }
            catch(Exception ex) {
                Log.e(TAG, "Invalid default value: " + defaultValue.toString());
            }
            persistInt(temp);
            mCurrentValue = temp;
        }
    }
}

这时需要在layout里写布局文件
seek_bar_preference.xml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/widget_frame"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:paddingLeft="15dp"
  android:paddingTop="5dp"
  android:paddingRight="10dp"
  android:paddingBottom="5dp"
  >
  <TextView android:id="@android:id/title"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="22dp"
    android:typeface="sans"
    android:textStyle="normal"
    android:textColor="#ffffff"
  ></TextView>
  <TextView android:id="@android:id/summary"
    android:layout_alignParentLeft="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@android:id/title"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefUnitsRight"
    android:layout_alignParentRight="true"
    android:layout_below="@android:id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefValue"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toLeftOf="@id/seekBarPrefUnitsRight"
    android:layout_below="@android:id/title"
    android:gravity="right"
  ></TextView>
  <TextView android:id="@+id/seekBarPrefUnitsLeft"
    android:layout_below="@android:id/title"
    android:layout_toLeftOf="@id/seekBarPrefValue"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  ></TextView>
  <LinearLayout android:id="@+id/seekBarPrefBarContainer"
    android:layout_alignParentLeft="true"
    android:layout_alignParentBottom="true"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@android:id/summary">
  </LinearLayout>
</RelativeLayout>

然后可以写进我们的activity的布局文件里了:

<com.sheng00.batterystatus.seekbarpreference
  sheng00:unitsright="%"
  sheng00:unitsleft=""
  android:dependency="@string/low_alert_checkbox"
  android:summary=" "
  android:title="@string/low_alert_level"
  sheng00:min="1"
  android:max="50"
  android:key="@string/low_alert_level_key"
  android:defaultvalue="15" />

效果如下图:
device-2011-12-21-115808

android.intent.action.MAIN与android.intent.category的作用

在android和ophone的应用程序可以有多个Activity,每个Activity是同级别的,那么在启动程序时,最先启动哪个Activity呢?

有些程序可能需要显示在程序列表里,有些不需要。怎么定义呢?

android.intent.action.MAIN决定应用程序最先启动的Activity 。
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。

因为你的程序可能有很多个activity,
只要xml配置文件中有这么一个intent-filter,而且里面有这个launcher,那么这个activity就是点击程序时最先运行的那个activity。

如果只有一个Activity,没有这两句也可以。