顯示具有 app 標籤的文章。 顯示所有文章
顯示具有 app 標籤的文章。 顯示所有文章

2015年10月14日 星期三

[Qt] Read Qss file (讀取QSS檔案)

qss file內容約為:

CImageBrowseDialog {
border: none;
background-image: url(Skins/CImageBrowseDialog/Common/004-back.jpg);
}

QPushButton#previousButton {
qproperty-geometry: rect(15 656 98 70);
background-image: url(Skins/CImageBrowseDialog/Common/004-normal_25.jpg);
}

QPushButton#previousButton:pressed {
background-image: url(Skins/CImageBrowseDialog/Common/004-push_25.jpg);
}

QPushButton#previousButton:disabled {
background-image: url(Skins/CImageBrowseDialog/Common/004-gray_25.jpg);
}

QPushButton#nextButton {
qproperty-geometry: rect(907 658 97 70);
background-image: url(Skins/CImageBrowseDialog/Common/004-normal_28.jpg);
}

QPushButton#nextButton:pressed {
background-image: url(Skins/CImageBrowseDialog/Common/004-push_28.jpg);
}

QPushButton#nextButton:disabled {
background-image: url(Skins/CImageBrowseDialog/Common/004-gray_28.jpg);
}

QLabel#PreLabel
{
  border: none;
  qproperty-geometry: rect(15 720 98 40);
  color : white;
}
 
QLabel#NextLabel
{
  border: none;
  qproperty-geometry: rect(907 720 98 40);
  color : white;
}


該如何讀取呢?

在main.cpp裡面

#include <QtGui/QApplication>
#include "mainwindow.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    QFile file("D:\\MyCode\\Qt\\CImageBrowseDialog(QSS file)\\COMMON.QSS");
    file.open(QFile::ReadOnly);
    QString styleSheet(file.readAll());
    qDebug()<<styleSheet;
    a.setStyleSheet(styleSheet);


    return a.exec();
}


讀取路徑可以設為相對(這邊是絕對路徑)

file.readAll()就會把所有的都讀近QString當中,最後設定application的setStyleSheet()即可完成

(當然UI介面要有相對應的button/label,objectName也要相同就是了)

END

2015年3月13日 星期五

[iOS] UDP Socket 實作-含程式碼 / 完整範例 / Youtube 實測

終於可以把udp socket 做出來了!

每次google 都是那幾篇.....而且每個都寫很不完整(很多都抄同一篇的)

搞了半天什麼CocoaAsyncSocket , GCDAsyncSocket , BSD Socket.....

沒有一篇寫比較完整,後來還好在github上有一個可以用的(不過是for Mac ,not for

iphone) 於是就仿照著寫了以後就可以用了!

--------------------------------------------------------------------------------------------------------------------------

(正文開始)

要寫socket 一定是要分兩部分 server & client , 然後在眾多的library裡面我選擇是:

AsyncUdpSocket

首先,先開一個project,然後add files to (project name)...

把AsyncUdpSocket.h / AsyncUdpSocket.m 加入(放哪邊不重要,不影響)




然後我們需要先到ViewController.h / Main.storyboard來宣告/拉一些物件


這邊(server)會需要一個輸入port 的textfield,一個按鈕 以及一個textview

別忘記要把他們兩邊做連結!


ViewControlloer.h:

//
//  ViewController.h
//  UdpServer
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015 daniel. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AsyncUdpSocket.h"

@interface ViewController : UIViewController
{
    AsyncUdpSocket *udpSocket;

}

@property (weak, nonatomic) IBOutlet UITextField *port;
@property (weak, nonatomic) IBOutlet UIButton *start;
@property (weak, nonatomic) IBOutlet UITextView *textview;

- (IBAction)startButton:(id)sender;


@end


接下來就是

ViewController.m:

//
//  ViewController.m
//  UdpServer
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015 daniel. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize port;
@synthesize start;
@synthesize textview;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];//初始化
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)startButton:(id)sender {
        //start udp server
        NSLog(@"Socket open");
        int port_int = [port.text intValue];
        if(port_int < 0 || port_int > 65535)
        {
            port_int = 0;
        }
        
        NSError *error = nil;
        
        if (![udpSocket bindToPort:port_int error:&error]) {
            return;
        }
        
        [udpSocket receiveWithTimeout:-1 tag:0];
        [port setEnabled:NO];
}

-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if(msg)
    {
        //textview.text  msg;
        NSLog(@"message is %@",msg);
        
        //以下這串是為了讓他能夠顯示在畫面上
        NSString *temp = [NSString stringWithFormat:@"%@\n",msg];
        NSMutableDictionary *attribute = [NSMutableDictionary dictionaryWithCapacity:1];
        NSAttributedString *as = [[NSAttributedString alloc] initWithString:temp attributes:attribute];
        //使用append的方式 ,但是他是NSAttributedString格式 所以才要先轉換,不能直接使用NSString!
        [[textview textStorage] appendAttributedString:as];
    }
    else
    {
        NSLog(@"converting UTF-8 Error");
    }
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}
@end


在viewDidLoad這邊就是app一開始會跑的地方,當然是把socket初始化

然後在button按下去觸發的這個函式(IBAction)startButton:(id)sender )

我們需要把使用者輸入的port 放進int port_int裡面

然後如果使用者輸入數字超過0~65535這個區間 就直接給他port = 0

接著在-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port

這一段,我們必須要先宣告一個NSData來接收資料(data),編碼這邊使用UTF-8

如果msg有東西則顯示在螢幕上

記得最後面要加

    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];

    [udpSocket receiveWithTimeout:-1 tag:0];

不然只能接收一次 !



--------------------------------------------------------------------------------------------------------------------------

然後就是 Client端了


一樣是把兩邊做連結(別忘了要import "AsyncUdpSocket.h")


//
//  ViewController.m
//  UdpClient
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015 daniel. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize addr;
@synthesize port;
@synthesize msg;
@synthesize sendButton;
@synthesize logView;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    
    if(![udpSocket bindToPort:0 error:&error])
    {
        NSLog(@"Error binding: %@",error);
        return;
    }
    
    [udpSocket receiveWithTimeout:-1 tag:0];
    
    NSLog(@"Ready");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(IBAction)send:(id)sender
{
    NSString *host = [addr text];
    NSLog(@"Address: %@",host);
    
    
    int port_int = [[port text] integerValue];//跟原本的不太一樣
    if(port_int <=0 || port > 65535)
    {
        NSLog(@"Valid port require");
    }
    
    NSString *message = [msg text];
    if (message.length == 0) {
        NSLog(@"Message require");
    }
    
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    
    if(data != nil)
        NSLog(@"data = %@",data);
    
    [udpSocket sendData:data toHost:host port:5000 withTimeout:-1 tag:tag];
}


-(void) onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
    //you could add checks here
}

- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
    // You could add checks here
}

-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if(msg)
    {
        NSLog(@"Receive: %@",msg);
    }
    else
    {
        NSLog(@"Receive Unknown message from %@:%hu",host,port);
    }
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}

@end

在viewDidLoad這邊一樣要先初始化udpSocket,然後在sendbutton觸發這個action的

event這邊:
-(IBAction)send:(id)sender
{
    NSString *host = [addr text];
    把使用者輸入的ip放入host變數   

    NSLog(@"Address: %@",host);
    
    
    int port_int = [port text];
    
    把使用者輸入的port放進去port_int變數   

    if(port_int <=0 || port > 65535)
    {
        NSLog(@"Valid port require");
    }
    
    NSString *message = [msg text];

    把使用者輸入的message放進去message變數

    if (message.length == 0) {
        NSLog(@"Message require");
    }
    
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    
   把要傳出去的message轉換為NSData型態,編碼使用utf-8

    if(data != nil)
        NSLog(@"data = %@",data);
    
    [udpSocket sendData:data toHost:host port:5000 withTimeout:-1 tag:tag];
    
    這邊為了測試方便直接把port 寫死5000,其實應該要寫port:port_int才對
}


好了!

這樣server / client 都有了 就可以開始通訊拉!




附上程式碼!


https://www.youtube.com/watch?v=wNX29RxA2K8&feature=youtu.be
https://www.youtube.com/watch?v=mDJv2UHnyZg&feature=youtu.be
附上實測證明可以用

2015年1月20日 星期二

[Android] 簡單氣象搜尋 (使用Yahoo Weather api)

氣象主要可以分為兩類:

1)使用地名(自行輸入)搜尋

2)使用座標(GPS)搜尋

這邊實作的部分是(1)

參考資料為:  zh-wang 在 Github上分享的程式碼

不過稍作修改-------下拉式更新天氣 , 跳出視窗式輸入地名

當然介面也有做調整,不過整體架構還是跟著參考資料修改而來的.


----------------------------------------

整個程式就分為3部分

1) 輸入地名(使用AlertDialog技術)

2) 下拉式更新(使用SwipeRefreshLayout技術)

3) 呼叫/解析Yahoo Weather Api 所傳回來的xml(呼叫yahoo Library)


先把MainActivity.class寫出來:

package com.example.weather_practice;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.civetcat.weather.library.WeatherInfo;
import com.civetcat.weather.library.YahooWeather;
import com.civetcat.weather.library.YahooWeather.SEARCH_MODE;
import com.civetcat.weather.library.YahooWeatherInfoListener;

public class MainActivity extends Activity implements YahooWeatherInfoListener {

private ImageView icon_img;
private TextView city_country_txv;
private TextView weather_status1_txv;
private TextView weather_status2_txv;
private TextView temperature_txv;
private AlertDialog dialog;
private static String City_Name;
private SwipeRefreshLayout laySwipe;

private YahooWeather mYahooWeather = YahooWeather.getInstance(5000, 5000, true);


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
        icon_img = (ImageView) findViewById(R.id.icon_img);
        city_country_txv = (TextView) findViewById(R.id.city_country_txv);
        weather_status1_txv = (TextView) findViewById(R.id.weather_status1_txv);
        weather_status2_txv = (TextView) findViewById(R.id.weather_status2_txv);
        temperature_txv = (TextView) findViewById(R.id.temperature_txv);    
       
        search_dialog();

initView();
        //searchByPlaceName("pingtung city");
}

private void search_dialog(){
// -----------取得Layout reference----------
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
final View view = inflater.inflate(R.layout.input_city, null);      
       
// -----------產生登入視窗--------
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("天氣查詢");
builder.setMessage("輸入查詢天氣城市名稱:(英文)");//"Input Target IP:"
builder.setView(view);
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
EditText edt = (EditText) view.findViewById(R.id.city_edt);
City_Name = edt.getText().toString();
Log.d("show",edt.getText().toString());
searchByPlaceName(edt.getText().toString());
}
});
builder.setNegativeButton("取消", null);
dialog = builder.create();
dialog.show();
}


private void initView(){
laySwipe = (SwipeRefreshLayout) findViewById(R.id.laySwipe);
laySwipe.setOnRefreshListener(onSwipeToRefresh);
laySwipe.setColorSchemeResources(
           android.R.color.holo_red_light,
           android.R.color.holo_blue_light,
           android.R.color.holo_green_light,
           android.R.color.holo_orange_light);
}

private OnRefreshListener onSwipeToRefresh = new OnRefreshListener(){

@Override
public void onRefresh() {
// TODO Auto-generated method stub
laySwipe.setRefreshing(true);
new Handler().postDelayed(new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
laySwipe.setRefreshing(false);
searchByPlaceName(City_Name);
Toast.makeText(getApplicationContext(), "Refresh done!", Toast.LENGTH_SHORT).show();
}},5000);
}};

private void searchByPlaceName(String location) {
mYahooWeather.setNeedDownloadIcons(true);
mYahooWeather.setSearchMode(SEARCH_MODE.PLACE_NAME);
Log.d("searchByPlaceName","searchByPlaceName");
mYahooWeather.queryYahooWeatherByPlaceName(getApplicationContext(), location, MainActivity.this);
}

@Override
public void gotWeatherInfo(WeatherInfo weatherInfo) {
// TODO Auto-generated method stub
// 屏東代碼2306213 or TWXX0015
Log.d("got weather info","got weather info");
        if (weatherInfo != null) {
        city_country_txv.setText(City_Name+ ", "+ weatherInfo.getWOEIDCountry());

        weather_status1_txv.setText(weatherInfo.getCurrentConditionDate());
        weather_status2_txv.setText(weatherInfo.getCurrentText());
       
        temperature_txv.setText(weatherInfo.getCurrentTempC()+"℃");

        Log.d("weather info",weatherInfo.getCurrentText());
if (weatherInfo.getCurrentConditionIcon() != null) {
//設定icon

switch(weatherInfo.getCurrentText()){
//不全部列舉,有些不會發生
case "Freezing Drizzle":
break;
case "Drizzle":
break;
case "Freezing Rain":
break;
case "Light Rain":
icon_img.setImageResource(R.drawable.rain_wh);
break;
case "Showers":
break;
case "Blustery":
break;
case "Windy":
break;
case "Cold":
break;
case "Cloudy":
break;
case "Mostly Cloudy":
icon_img.setImageResource(R.drawable.double_cloud_wh);
break;
case "Partly Cloudy":
icon_img.setImageResource(R.drawable.cloud_wh);
break;
case "Clear": //night
break;
case "Sunny":
break;
case "Fair": //day or night
icon_img.setImageResource(R.drawable.night_wh);
break;
case "Hot":
break;
case "Isolated Thunderstorms":
break;
case "Scattered Thunderstorms":
break;
case "Scattered Showers":
break;
case "Thundershowers":
break;
case "Isolated Thundershowers":
break;
case "Haze":
icon_img.setImageResource(R.drawable.haze_wh);
break;
case "Fog":
icon_img.setImageResource(R.drawable.haze_wh);
break;
case "not available":
break;
}
}
        } else {
        }
}



@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;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}


********在這邊特別註明一下,yahoo有些天氣狀態還沒更新上去,所以switch case的部分要自行做調整(不過不影響整個程式碼運行)*******


search_dialog()函式就是負責跳出視窗讓使用者可以輸入地名,查詢天氣

initView() 則是初始化下拉式更新的元件

OnRefreshListener() 就監聽 沒別的 onRefresh()裡面就寫你更新時要做的動作,至於handler只是

因為要show toast而已,沒太大用處:)

searchByPlaceName() 這個很重要,他會呼叫到yahoo library 透過

SEARCH_MODE.PLACE_NAME 這方式來搜尋天氣

然後因為我們一開頭有implement YahooWeatherInfoListener 所以他會自己監聽,(裡面有一個函式gotWeatherInfo,就是listener 實作的方法)


詳細的就請大家自己看一下囉,應該不難才對(?)


Activity_main.xml:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/laySwipe"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#87CEFA"
    android:orientation="vertical"
    tools:context="ah.hathi.simpleweather.WeatherActivity"
    tools:ignore="MergeRootFrame" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/city_country_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_vertical_margin"
            android:gravity="center"
            android:text="城市,國家"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <ImageView
            android:id="@+id/icon_img"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/sun_wh" />

        <TextView
            android:id="@+id/weather_status1_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="天氣狀態1"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/weather_status2_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="天氣狀態2"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0.5" >
        </FrameLayout>

        <TextView
            android:id="@+id/temperature_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/activity_vertical_margin"
            android:gravity="center"
            android:text="溫度"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textSize="@dimen/temperature_text_size" />
    </LinearLayout>

</android.support.v4.widget.SwipeRefreshLayout>


input_city.xml:

<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/city_edt"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</EditText>

然後再values/dimens.xml 還有宣告一個

<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="temperature_text_size">30dp</dimen>

</resources>

修改這邊就可以方便修改溫度的字型大小




附上完整檔案,以上 


End


2015年1月14日 星期三

[Android] 基礎Google Map教學

終於把這個很煩人的google map弄出一點樣子

寫在這邊紀錄一下

可能會產生的錯誤會有幾種

1)  INSTALL_FAILED_MISSING_SHARED_LIBRARY Error

2) API Key failed

3) Permission denied



第一種很顯然你刷機(flash ROM)時候法google libary沒有匯入

第二種則是API Key你沒有用你專屬的key ->請到 https://console.developers.google.com/ 申請一

個,申請詳細辦法






切記!!! 你的package name要正確,不正確會無法顯示地圖!!

就把SHA1;package.name輸入在空格中,建立,然後就有API key了

第三種解決方式就是檢查你的AndroidManifest.xml是否有加入適當的permission


-------------------------------------------------------------------------------------------------------------------


以下為三項基礎

1.google play library

首先開啟SDK Manager ->檢查google play service (以下用圖來表示)








有錯誤一定是沒有import正確 / 沒有加入external jar files

然後



這部分需要開啟權限




最後原本的網址載點在這邊

https://github.com/googlemaps/hellomap-android

程式碼跟layout可以上去下載來看看

layout:

<?xml version="1.0" encoding="utf-8"?>
<!--
See this page for more XML attribute options
https://developers.google.com/maps/documentation/android/map#using_xml_attributes
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:map="http://schemas.android.com/apk/res-auto"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="com.google.android.gms.maps.SupportMapFragment"
          map:mapType="normal"/>




MainActivity:

package com.example.hellomap;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MainActivity extends FragmentActivity {
    private GoogleMap mMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}


就這樣! 

完成圖 End

2014年8月12日 星期二

[Android] UDP Receive / Send 完整-可執行-附檔案-教學

花了兩三個禮拜終於把Android UDP搞定!

首先,要先搞懂Thread / Handler是甚麼,不然這篇往下看沒有意義(因為會看不懂)

在MainActivity的部分,這邊負責主要的UI介面+Handler+Thread呼叫

package com.example.thread_example;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import android.annotation.SuppressLint;
import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.support.v7.app.ActionBarActivity;
import android.text.format.Time;
import android.util.Log;
import android.widget.TextView;

@SuppressLint("NewApi")
public class MainActivity extends ActionBarActivity {

public static Handler exHandler;
private TextView txv;
private ChatServer chatserver;
private ChatSender chatsender;
public static InetAddress IP;
public WifiInfo mwifiInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (android.os.Build.VERSION.SDK_INT > 9) {
   StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
   StrictMode.setThreadPolicy(policy);
}

txv = (TextView) findViewById(R.id.textView);
//利用handler來顯示接收到的文字
exHandler=new Handler() {
       @Override
       public void handleMessage(Message msg) {
        super.handleMessage(msg);
        String msgString = (String)msg.obj;
        Log.d("Handler","Now in Handler");
        txv.setText(null);
        txv.setText(msgString+"\n"+txv.getText().toString());
       }
   };
        //獲得Wifi的內部網路IP
   StringBuilder IFCONFIG=new StringBuilder();
   try {
       for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
           NetworkInterface intf = en.nextElement();
           for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
               InetAddress inetAddress = enumIpAddr.nextElement();
               if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress()) {
               IFCONFIG.append(inetAddress.getHostAddress().toString()+"\n");              
               }
           }
       }
       txv.setText(IFCONFIG.toString());
       Log.d("LOG_Text", IFCONFIG.toString());
   } catch (SocketException ex) {
       Log.e("LOG_TAG", ex.toString());
   }


try{
chatserver = new ChatServer();
chatserver.start();
chatsender = new ChatSender();
chatsender.start();
Log.d("User","Thread start...");

}catch(Exception e)
{
String str = e.toString();
Log.e("Error by User", str);
}

}

protected void onPause(){
super.onPause();
if(chatserver != null)
{
if(!chatserver.isInterrupted())
{
chatserver.interrupt();
}
}
}

}

有一點長,這邊元件只有拉一個TextView而已,十分簡單。

IFCONFIG 

這邊負責顯示WIFI的IP

Thread--chatserver/chatsender

則是另外開兩個java檔(與mainActivity.java同層)分別做為接收與傳送,.start()就是讓他啟動而已。

exHandler

這邊負責顯示接收到的資訊(不能用static來傳值,因為Android不支援,至於為什麼我也不清楚),並把他印出來在textview上面。



Receiver部分(chatserver.java)

package com.example.thread_example;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

import android.os.Bundle;
import android.os.Message;
import android.util.Log;

public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 8000;
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
public void run(){

byte[] byte1024 = new byte[1024];
//Message msg = new Message();
//Bundle data = new Bundle();
DatagramPacket dPacket = new DatagramPacket(byte1024, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
while(true)
{
//印出來到螢幕上
txt = new String(byte1024, 0, dPacket.getLength());
MainActivity.exHandler.sendMessage(MainActivity.exHandler.obtainMessage(1,txt));
Log.d("User","Handler send Message");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
private void CloseSocket(DatagramSocket socket) throws IOException{
socket.close();
}
}

這邊宣告一個1024的byte來接收資料(按照你的資料量大小來調整宣告大小)

一定要宣告datagramSocket,datagramPacket,一個是連線,一個是接收封包用,至於handler這邊的

sendMessage就是回傳到MainActivity來讓textview顯示接收的資訊而已。結構上有兩個while(),第

一個while會卡在receive()這邊,一直到有封包進來才會往下跑到第二個while(),第二個則是印出資

訊,沒有甚麼特別的地方(Log是debug用的)



2014年3月7日 星期五

[Android] Google Android APP 開發環境安裝

1.需要Java JDK

http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

選擇符合自己作業系統的版本

2.下載

http://developer.android.com/sdk/index.html

installer_r20.0.1-windows.exe  + ADT bundle for windows

3.安裝installer_r20.0.1 (要調整為install for anyone using this computer ,預設為just for me)

下一步下一步......完成

4.打開Android SDK Manager 選 Android其中一個版本 然後按下install X(看有多少個) Packages...

會開始更新,很久,可以休息一下喝杯水再過來

5.改JAVA環境變數(跟linux根本一樣)

到[系統及安全性]->[系統]->[進階系統設定](在左側) 進入以後 選 [進階]->下面有{環境變數} 按鈕,進入以後


(如文字描述)

將你安裝的JDK的bin資料夾路徑ex: C:\Program Files\Java\jdk1.7.0_51\bin 加入 "系統變數"的Path值中,如果前面有東西,或後面還要加東西請用分號區隔。

然後再加入Android SDK tools & Platform-tools兩個資料夾(也在program files\android....可以找到)

所以總共是:

加入;C:\Program Files\Android\android-sdk\tools;C:\Program Files\Android\android-sdk\platform-tools

;是為了區隔前後,不是打錯(以上三個都要(編輯)加入在Path中)

選取 "系統變數"的CLASSPATH(如果沒有就新增) 按 編輯 加入  C:\Program Files\Java\jdk1.7.0_51\lib (是lib資料夾,不是bin)

6.開始->程式->Android SDK tools ->AVD Manager

按New即可新增一個模擬器,設定可以自己調。(要調整SD卡的話一定要給sdcard空間,不然權限會不足)->按下Start就會開始emulate(模擬),超級超級超級久.....然後就可以測試囉!

7.cmd 命令提式字元 先進到platform-tools目錄

adb.exe shell( root權限 Linux指令)

adb.exe push 檔案 手機內的路徑(pull為下載,push為上傳)

可以在Android SDK 下的tools 找到ddms.bat 打開可以看file explore 或是模擬傳簡訊。

End